Test Failed
Branch master (ac52e0)
by compolom
03:38 queued 01:44
created

GD::tmp()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 12
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 2.9765

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 7
nc 2
nop 1
dl 0
loc 12
ccs 3
cts 8
cp 0.375
crap 2.9765
rs 10
c 1
b 0
f 0
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
13
{
14
    /**
15
     * GD constructor.
16
     * @param string $image
17
     * @throws Exception
18
     */
19 4
    public function __construct(string $image)
20
    {
21 4
        $this->init($image);
22
    }
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
    public function brightness(int $level): ImageInterface
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);
0 ignored issues
show
Bug introduced by
It seems like $this->getImage() can also be of type Imagick; however, parameter $image of imagefilter() 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

62
        imagefilter(/** @scrutinizer ignore-type */ $this->getImage(), IMG_FILTER_BRIGHTNESS, $level);
Loading history...
63
64
        return $this;
65
    }
66
67
    /**
68
     * @param int $level
69
     * @return ImageInterface
70
     */
71
    public function contrast(int $level): ImageInterface
72
    {
73
        if (!$this->compareRangeValue($level, 100))
74
        {
75
            throw new InvalidArgumentException('Wrong contrast level, range -100 - 100, ' . $level . ' given');
76
        }
77
        imagefilter($this->getImage(), IMG_FILTER_CONTRAST, $level);
0 ignored issues
show
Bug introduced by
It seems like $this->getImage() can also be of type Imagick; however, parameter $image of imagefilter() 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

77
        imagefilter(/** @scrutinizer ignore-type */ $this->getImage(), IMG_FILTER_CONTRAST, $level);
Loading history...
78
79
        return $this;
80
    }
81
82
    /**
83
     * @return ImageInterface
84
     */
85
    public function negate(): ImageInterface
86
    {
87
        imagefilter($this->getImage(), IMG_FILTER_NEGATE);
0 ignored issues
show
Bug introduced by
It seems like $this->getImage() can also be of type Imagick; however, parameter $image of imagefilter() 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

87
        imagefilter(/** @scrutinizer ignore-type */ $this->getImage(), IMG_FILTER_NEGATE);
Loading history...
88
89
        return $this;
90
    }
91
92
    /**
93
     * @return ImageInterface
94
     */
95
    public function blur(): ImageInterface
96
    {
97
        for ($i = 0; $i < 30; $i++) {
98
            if ($i % 5 === 0) {
99
                imagefilter($this->getImage(), IMG_FILTER_SMOOTH, -7);
0 ignored issues
show
Bug introduced by
It seems like $this->getImage() can also be of type Imagick; however, parameter $image of imagefilter() 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

99
                imagefilter(/** @scrutinizer ignore-type */ $this->getImage(), IMG_FILTER_SMOOTH, -7);
Loading history...
100
            }
101
            imagefilter($this->getImage(), IMG_FILTER_GAUSSIAN_BLUR);
102
        }
103
104
        return $this;
105
    }
106
107
    /**
108
     * @return ImageInterface
109
     */
110
    public function flip(): ImageInterface
111
    {
112
        imageflip($this->getImage(), IMG_FLIP_VERTICAL);
0 ignored issues
show
Bug introduced by
It seems like $this->getImage() can also be of type Imagick; however, parameter $image of imageflip() 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

112
        imageflip(/** @scrutinizer ignore-type */ $this->getImage(), IMG_FLIP_VERTICAL);
Loading history...
113
114
        return $this;
115
    }
116
117
    /**
118
     * @return ImageInterface
119
     */
120
    public function flop(): ImageInterface
121
    {
122
        imageflip($this->getImage(), IMG_FLIP_HORIZONTAL);
0 ignored issues
show
Bug introduced by
It seems like $this->getImage() can also be of type Imagick; however, parameter $image of imageflip() 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

122
        imageflip(/** @scrutinizer ignore-type */ $this->getImage(), IMG_FLIP_HORIZONTAL);
Loading history...
123
124
        return $this;
125
    }
126
127
    /**
128
     * @return ImageInterface
129
     */
130
    public function grayscale(): ImageInterface
131
    {
132
        imagefilter($this->getImage(), IMG_FILTER_GRAYSCALE);
0 ignored issues
show
Bug introduced by
It seems like $this->getImage() can also be of type Imagick; however, parameter $image of imagefilter() 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

132
        imagefilter(/** @scrutinizer ignore-type */ $this->getImage(), IMG_FILTER_GRAYSCALE);
Loading history...
133
134
        return $this;
135
    }
136
137
    /**
138
     * @param string $text
139
     * @param string $font
140
     * @param string $position
141
     * @return $this
142
     * @throws InvalidArgumentException
143
     * @throws Exception
144
     */
145
    public function copyright(string $text, string $font, string $position = 'SouthWest'): ImageInterface
146
    {
147
        if (!array_key_exists(strtoupper($position), self::POSITIONS)) {
148
            throw new InvalidArgumentException('Wrong position');
149
        }
150
151
        imagecopymerge(
152
            $this->getImage(),
0 ignored issues
show
Bug introduced by
It seems like $this->getImage() can also be of type Imagick; however, parameter $dst_im of imagecopymerge() 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

152
            /** @scrutinizer ignore-type */ $this->getImage(),
Loading history...
153
            $image = $this->prepareImage($text, $font),
154
            (int) ((($this->getWidth() - imagesx($image)) / 2) * self::POSITIONS[strtoupper($position)]['x']) + self::POSITIONS[strtoupper($position)]['padX'],
155
            (int) ((($this->getHeight() - imagesy($image)) / 2) * self::POSITIONS[strtoupper($position)]['y']) + self::POSITIONS[strtoupper($position)]['padY'],
156
            0,
157
            0,
158
            $this->getWidth(),
159
            $this->getHeight(),
160
            80
161
        );
162
163
        return $this;
164
    }
165
166
    /**
167
     * @param string $text
168
     * @param string $font
169
     * @return resource
170
     * @throws InvalidArgumentException
171
     * @throws Exception
172
     */
173
    private function prepareImage(string $text, string $font)
174
    {
175
        if (!$coordinates = imagettfbbox($fontSize = 15, 0, $font, $text)) {
176
            throw new InvalidArgumentException('Does not support font');
177
        }
178
179
        $minX = min([$coordinates[0], $coordinates[2], $coordinates[4], $coordinates[6]]);
180
        $maxX = max([$coordinates[0], $coordinates[2], $coordinates[4], $coordinates[6]]);
181
        $minY = min([$coordinates[1], $coordinates[3], $coordinates[5], $coordinates[7]]);
182
        $maxY = max([$coordinates[1], $coordinates[3], $coordinates[5], $coordinates[7]]);
183
        $textX = (int) abs($minX) + 1;
184
        $textY = (int) abs($minY) + 1;
185
        $image = $this->newImage($maxX - $minX + 2, $maxY - $minY + 2);
186
        imagecolortransparent($image, $white = imagecolorallocate($image, 0, 0, 0));
187
        imagefilledrectangle($image, 0, 0, $this->getWidth(), 20, $white);
188
        imagettftext($image, $fontSize, 0, $textX, $textY, $white, $font, $text);
189
        imagettftext($image, $fontSize, 0, $textX + 1, $textY + 1, $blue = imagecolorallocate($image, 0, 128, 128),
190
            $font, $text);
191
        imagettftext($image, $fontSize, 0, $textX + 1, $textY + 1, $red = imagecolorallocate($image, 255, 0, 0), $font,
192
            $text);
193
        imagettftext($image, $fontSize, 0, $textX + 2, $textY + 2, $black = imagecolorallocate($image, 255, 255, 255),
194
            $font, $text);
195
        imagettftext($image, $fontSize, 0, $textX + 2, $textY + 2, $gray = imagecolorallocate($image, 128, 128, 128),
196
            $font, $text);
197
198
        return $image;
199
    }
200
201
    /**
202
     * @param int $width
203
     * @param int $height
204
     * @return resource
205
     */
206
    protected function newImage(int $width, int $height)
207
    {
208
        $newimage = imagecreatetruecolor($width, $height);
209
        $transparent = imagecolorallocatealpha($newimage, 255, 255, 255, 127);
210
        imagefill($newimage, 0, 0, $transparent);
211
        imagealphablending($newimage, true);
212
        imagesavealpha($newimage, true);
213
214
        return $newimage;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $newimage also could return the type GdImage which is incompatible with the documented return type resource.
Loading history...
215
    }
216
217
    /**
218
     * @param int $width
219
     * @param int $height
220
     * @return ImageInterface
221
     */
222
    public function resize(int $width, int $height): ImageInterface
223
    {
224
        $newimage = $this->newImage($width, $height);
225
        imagecopyresampled($newimage, $this->getImage(), 0, 0, 0, 0, $width, $height, $this->getWidth(),
0 ignored issues
show
Bug introduced by
It seems like $this->getImage() can also be of type Imagick; however, parameter $src_image of imagecopyresampled() 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

225
        imagecopyresampled($newimage, /** @scrutinizer ignore-type */ $this->getImage(), 0, 0, 0, 0, $width, $height, $this->getWidth(),
Loading history...
226
            $this->getHeight());
227
        $this->setImage($newimage);
228
        $this->setSizes();
229
230
        return $this;
231
    }
232
233
    protected function setSizes(): void
234
    {
235
        $this->setWidth(imagesx($this->getImage()));
0 ignored issues
show
Bug introduced by
It seems like $this->getImage() can also be of type Imagick; however, parameter $image of imagesx() 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

235
        $this->setWidth(imagesx(/** @scrutinizer ignore-type */ $this->getImage()));
Loading history...
236
        $this->setHeight(imagesy($this->getImage()));
0 ignored issues
show
Bug introduced by
It seems like $this->getImage() can also be of type Imagick; however, parameter $image of imagesy() 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

236
        $this->setHeight(imagesy(/** @scrutinizer ignore-type */ $this->getImage()));
Loading history...
237
        $this->setOrientation();
238
    }
239
240
    /**
241
     * @param int $width
242
     * @param int $height
243
     * @param int $x
244
     * @param int $y
245
     * @return ImageInterface
246
     */
247
    public function crop(int $width, int $height, int $x, int $y): ImageInterface
248
    {
249
        $width -= $x;
250
        $height -= $y;
251
        $newimage = $this->newImage($width, $height);
252
        imagecopyresampled($newimage, $this->getImage(), 0, 0, $x, $y, $width, $height, $width, $height);
0 ignored issues
show
Bug introduced by
It seems like $this->getImage() can also be of type Imagick; however, parameter $src_image of imagecopyresampled() 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

252
        imagecopyresampled($newimage, /** @scrutinizer ignore-type */ $this->getImage(), 0, 0, $x, $y, $width, $height, $width, $height);
Loading history...
253
        $this->setImage($newimage);
254
        $this->setSizes();
255
256
        return $this;
257
    }
258
259
    /**
260
     * @param int $angle
261
     * @return ImageInterface
262
     */
263
    public function rotate(int $angle = 90): ImageInterface
264
    {
265
        $angle *= -1;
266
        $transparent = imagecolorallocatealpha($this->image, 0, 0, 0, 127);
267
        $rotate = imagerotate($this->getImage(), $angle, $transparent);
0 ignored issues
show
Bug introduced by
It seems like $this->getImage() can also be of type Imagick; however, parameter $image of imagerotate() 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

267
        $rotate = imagerotate(/** @scrutinizer ignore-type */ $this->getImage(), $angle, $transparent);
Loading history...
268
        imagealphablending($rotate, true);
269
        imagesavealpha($rotate, true);
270
        $this->setImage($rotate);
271
        $this->setSizes();
272
273
        return $this;
274
    }
275
276
    /**
277
     * @throws LogicException
278
     * @throws RangeException
279
     * @return string
280
     */
281
    public function __toString(): string
282
    {
283
        $temp = new SplFileObject(tempnam(sys_get_temp_dir(), 'image' . mt_rand()), 'w+');
284
        imagepng($this->getImage(), $temp->getRealPath(), 9, PNG_ALL_FILTERS);
0 ignored issues
show
Bug introduced by
It seems like $this->getImage() can also be of type Imagick; however, parameter $image of imagepng() 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

284
        imagepng(/** @scrutinizer ignore-type */ $this->getImage(), $temp->getRealPath(), 9, PNG_ALL_FILTERS);
Loading history...
285
286
        return trim(file_get_contents($temp->getRealPath()));
287
    }
288
289
    /**
290
     * @param string $filename
291
     * @param int $quality
292
     * @return bool
293
     */
294
    public function save(string $filename, $quality = 100): bool
295
    {
296
        return imagepng($this->getImage(), $filename . '.png', (int) ($quality / 11), PNG_ALL_FILTERS);
0 ignored issues
show
Bug introduced by
It seems like $this->getImage() can also be of type Imagick; however, parameter $image of imagepng() 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

296
        return imagepng(/** @scrutinizer ignore-type */ $this->getImage(), $filename . '.png', (int) ($quality / 11), PNG_ALL_FILTERS);
Loading history...
297
    }
298
299
    /**
300
     * @param int $width
301
     * @param int $height
302
     * @param int $newWidth
303
     * @param int $newHeight
304
     * @return ImageInterface
305
     */
306
    protected function prepareThumbnail(
307
        int $width,
308
        int $height,
309
        int $newWidth = 0,
310
        int $newHeight = 0
311
    ): ImageInterface {
312
        imagecopyresampled(
313
            $newimage = $this->newImage($width, $height),
314
            $this->getImage(),
0 ignored issues
show
Bug introduced by
It seems like $this->getImage() can also be of type Imagick; however, parameter $src_image of imagecopyresampled() 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

314
            /** @scrutinizer ignore-type */ $this->getImage(),
Loading history...
315
            0 - (int) (($newWidth - $width) / 2),
316
            0 - (int) (($newHeight - $height) / 2),
317
            0,
318
            0,
319
            $newWidth,
320
            $newHeight,
321
            $this->getWidth(),
322
            $this->getHeight()
323
        );
324
        $this->setImage($newimage);
325
        $this->setSizes();
326
327
        return $this;
328
    }
329
330
    /**
331
     * @param string $source
332
     * @return ImageInterface
333
     * @throws InvalidArgumentException
334
     * @throws Exception
335
     */
336 3
    protected function tmp(string $source): ImageInterface
337
    {
338 3
        if (!$image = @imagecreatefromstring($source)) {
339 3
            throw new InvalidArgumentException('Image create failed');
340
        }
341
        $this->setImage($image);
342
        $this->setSizes();
343
        // save transparent
344
        imagesavealpha($this->getImage(), true);
345
        imagealphablending($this->getImage(), false);
346
347
        return $this;
348
    }
349
350
    /**
351
     * @param ImageInterface $watermark
352
     * @param int $x
353
     * @param int $y
354
     * @return ImageInterface
355
     */
356
    protected function prepareWatermark($watermark, int $x, int $y): ImageInterface
357
    {
358
        imagealphablending($this->getImage(), true);
0 ignored issues
show
Bug introduced by
It seems like $this->getImage() can also be of type Imagick; 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

358
        imagealphablending(/** @scrutinizer ignore-type */ $this->getImage(), true);
Loading history...
359
        imagesavealpha($this->getImage(), true);
0 ignored issues
show
Bug introduced by
It seems like $this->getImage() can also be of type Imagick; 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

359
        imagesavealpha(/** @scrutinizer ignore-type */ $this->getImage(), true);
Loading history...
360
        imagecopyresampled(
361
            $this->getImage(),
0 ignored issues
show
Bug introduced by
It seems like $this->getImage() can also be of type Imagick; however, parameter $dst_image of imagecopyresampled() 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

361
            /** @scrutinizer ignore-type */ $this->getImage(),
Loading history...
362
            $watermark->getImage(),
0 ignored issues
show
Bug introduced by
It seems like $watermark->getImage() can also be of type Imagick; however, parameter $src_image of imagecopyresampled() 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

362
            /** @scrutinizer ignore-type */ $watermark->getImage(),
Loading history...
363
            $x,
364
            $y,
365
            0,
366
            0,
367
            $width = $watermark->getWidth(),
0 ignored issues
show
Bug introduced by
The method getWidth() does not exist on Compolomus\Compomage\Interfaces\ImageInterface. Since it exists in all sub-types, consider adding an abstract or default implementation to Compolomus\Compomage\Interfaces\ImageInterface. ( Ignorable by Annotation )

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

367
            $width = $watermark->/** @scrutinizer ignore-call */ getWidth(),
Loading history...
368
            $height = $watermark->getHeight(),
0 ignored issues
show
Bug introduced by
The method getHeight() does not exist on Compolomus\Compomage\Interfaces\ImageInterface. Since it exists in all sub-types, consider adding an abstract or default implementation to Compolomus\Compomage\Interfaces\ImageInterface. ( Ignorable by Annotation )

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

368
            $height = $watermark->/** @scrutinizer ignore-call */ getHeight(),
Loading history...
369
            $width,
370
            $height
371
        );
372
373
        return $this;
374
    }
375
}
376