Passed
Push — master ( 8718bd...547bf2 )
by compolom
02:24
created

GD::rotate()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 12
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 12
ccs 9
cts 9
cp 1
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 9
nc 1
nop 1
crap 1
1
<?php declare(strict_types=1);
2
3
namespace Compolomus\Compomage;
4
5
use Compolomus\Compomage\Interfaces\ImageInterface;
6
7
class GD extends AbstractImage implements ImageInterface
8
{
9
    /**
10
     * @var resource
11
     */
12
    private $image;
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
    public function flip(): ImageInterface
25
    {
26
        imageflip($this->getImage(), IMG_FLIP_VERTICAL);
27
28
        return $this;
29
    }
30
31
    /**
32
     * @return resource
33
     */
34 9
    public function getImage()
35
    {
36 9
        return $this->image;
37
    }
38
39 8
    public function setImage($image): void
40
    {
41 8
        $this->image = $image;
42 8
    }
43
44
    public function flop(): ImageInterface
45
    {
46
        imageflip($this->getImage(), IMG_FLIP_HORIZONTAL);
47
48
        return $this;
49
    }
50
51
    public function grayscale(): ImageInterface
52
    {
53
        imagefilter($this->getImage(), IMG_FILTER_GRAYSCALE);
54
55
        return $this;
56
    }
57
58
    /**
59
     * @param string $text
60
     * @param string $font
61
     * @param string $position
62
     * @return $this
63
     * @throws \InvalidArgumentException
64
     * @throws \Exception
65
     */
66 1
    public function copyright(string $text, string $font, string $position = 'SouthWest'): ImageInterface
67
    {
68 1
        if (!array_key_exists(strtoupper($position), self::POSITIONS)) {
69 1
            throw new \InvalidArgumentException('Wrong position');
70
        }
71
72
        imagecopymerge(
73
            $this->getImage(),
74
            $image = $this->prepareImage($text, $font),
75
            (int)((($this->getWidth() - imagesx($image)) / 2) * self::POSITIONS[strtoupper($position)]['x']) + self::POSITIONS[strtoupper($position)]['padX'],
76
            (int)((($this->getHeight() - imagesy($image)) / 2) * self::POSITIONS[strtoupper($position)]['y']) + self::POSITIONS[strtoupper($position)]['padY'],
77
            0,
78
            0,
79
            $this->getWidth(),
80
            $this->getHeight(),
81
            80
82
        );
83
84
        return $this;
85
    }
86
87
    /**
88
     * @param string $text
89
     * @param string $font
90
     * @return resource
91
     * @throws \InvalidArgumentException
92
     * @throws \Exception
93
     */
94
    private function prepareImage(string $text, string $font)
95
    {
96
        if (!$coordinates = imagettfbbox($fontSize = 15, 0, $font, $text)) {
97
            throw new \InvalidArgumentException('Does not support font');
98
        }
99
100
        $minX = min([$coordinates[0], $coordinates[2], $coordinates[4], $coordinates[6]]);
101
        $maxX = max([$coordinates[0], $coordinates[2], $coordinates[4], $coordinates[6]]);
102
        $minY = min([$coordinates[1], $coordinates[3], $coordinates[5], $coordinates[7]]);
103
        $maxY = max([$coordinates[1], $coordinates[3], $coordinates[5], $coordinates[7]]);
104
        $textX = (int)abs($minX) + 1;
105
        $textY = (int)abs($minY) + 1;
106
        $image = $this->newImage($maxX - $minX + 2, $maxY - $minY + 2);
107
        imagecolortransparent($image, $white = imagecolorallocate($image, 0, 0, 0));
108
        imagefilledrectangle($image, 0, 0, $this->getWidth(), 20, $white);
109
        imagettftext($image, $fontSize, 0, $textX, $textY, $white, $font, $text);
110
        imagettftext($image, $fontSize, 0, $textX + 1, $textY + 1, $blue = imagecolorallocate($image, 0, 128, 128),
111
            $font, $text);
112
        imagettftext($image, $fontSize, 0, $textX + 1, $textY + 1, $red = imagecolorallocate($image, 255, 0, 0), $font,
113
            $text);
114
        imagettftext($image, $fontSize, 0, $textX + 2, $textY + 2, $black = imagecolorallocate($image, 255, 255, 255),
115
            $font, $text);
116
        imagettftext($image, $fontSize, 0, $textX + 2, $textY + 2, $gray = imagecolorallocate($image, 128, 128, 128),
117
            $font, $text);
118
119
        return $image;
120
    }
121
122
    /**
123
     * @param int $width
124
     * @param int $height
125
     * @return resource
126
     */
127 3
    private function newImage(int $width, int $height)
128
    {
129 3
        $newimage = imagecreatetruecolor($width, $height);
130 3
        $transparent = imagecolorallocatealpha($newimage, 255, 255, 255, 127);
131 3
        imagefill($newimage, 0, 0, $transparent);
132 3
        imagealphablending($newimage, true);
133 3
        imagesavealpha($newimage, true);
134
135 3
        return $newimage;
136
    }
137
138
    /**
139
     * @param int $width
140
     * @param int $height
141
     * @return ImageInterface
142
     */
143 2
    public function resize(int $width, int $height): ImageInterface
144
    {
145 2
        $newimage = $this->newImage($width, $height);
146 2
        imagecopyresampled($newimage, $this->getImage(), 0, 0, 0, 0, $width, $height, $this->getWidth(),
147 2
            $this->getHeight());
148 2
        $this->setImage($newimage);
149 2
        $this->setSizes();
150
151 2
        return $this;
152
    }
153
154 8
    protected function setSizes(): void
155
    {
156 8
        $this->setWidth(imagesx($this->getImage()));
157 8
        $this->setHeight(imagesy($this->getImage()));
158 8
    }
159
160
    /**
161
     * @param int $width
162
     * @param int $height
163
     * @param int $x
164
     * @param int $y
165
     * @return ImageInterface
166
     */
167
    public function crop(int $width, int $height, int $x, int $y): ImageInterface
168
    {
169
        $width -= $x;
170
        $height -= $y;
171
        $newimage = $this->newImage($width, $height);
172
        imagecopyresampled($newimage, $this->getImage(), 0, 0, $x, $y, $width, $height, $width, $height);
173
        $this->setImage($newimage);
174
        $this->setSizes();
175
176
        return $this;
177
    }
178
179
    /**
180
     * @param int $angle
181
     * @return ImageInterface
182
     */
183 1
    public function rotate(int $angle = 90): ImageInterface
184
    {
185 1
        $angle *= -1;
186 1
        $transparent = imagecolorallocatealpha($this->image, 0, 0, 0, 127);
187 1
        $rotate = imagerotate($this->getImage(), $angle, $transparent);
188 1
        imagealphablending($rotate, true);
189 1
        imagesavealpha($rotate, true);
190 1
        $this->setImage($rotate);
191 1
        $this->setSizes();
192
193 1
        return $this;
194
    }
195
196
    /**
197
     * @throws \LogicException
198
     * @throws \RangeException
199
     * @return string
200
     */
201 1
    public function __toString(): string
202
    {
203 1
        $temp = new \SplFileObject(tempnam(sys_get_temp_dir(), 'image' . rand()), 'w+');
204 1
        imagepng($this->getImage(), $temp->getRealPath(), 9, PNG_ALL_FILTERS);
205 1
        $temp->rewind();
206 1
        $tmp = '';
207
208 1
        foreach ($temp as $line) {
209 1
            $tmp .= $line;
210
        }
211
212 1
        return trim($tmp);
213
    }
214
215
    /**
216
     * @param string $filename
217
     * @param int $quality
218
     * @return bool
219
     */
220 1
    public function save(string $filename, $quality = 100): bool
221
    {
222 1
        return imagepng($this->getImage(), $filename . '.png', (int)($quality / 11), PNG_ALL_FILTERS);
223
    }
224
225
    /**
226
     * @param int $width
227
     * @param int $height
228
     * @param int $newWidth
229
     * @param int $newHeight
230
     * @return ImageInterface
231
     */
232 1
    protected function prepareThumbnail(
233
        int $width,
234
        int $height,
235
        int $newWidth = 0,
236
        int $newHeight = 0
237
    ): ImageInterface {
238 1
        imagecopyresampled(
239 1
            $newimage = $this->newImage($width, $height),
240 1
            $this->getImage(),
241 1
            0 - (int)(($newWidth - $width) / 2),
242 1
            0 - (int)(($newHeight - $height) / 2),
243 1
            0,
244 1
            0,
245 1
            $newWidth,
246 1
            $newHeight,
247 1
            $this->getWidth(),
248 1
            $this->getHeight()
249
        );
250 1
        $this->setImage($newimage);
251 1
        $this->setSizes();
252
253 1
        return $this;
254
    }
255
256
    /**
257
     * @param string $source
258
     * @return ImageInterface
259
     * @throws \InvalidArgumentException
260
     * @throws \Exception
261
     */
262 8
    protected function tmp(string $source): ImageInterface
263
    {
264 8
        if (@!\is_resource($image = @imagecreatefromstring($source))) {
265 1
            throw new \InvalidArgumentException('Image create failed');
266
        }
267 7
        $this->setImage($image);
268 7
        $this->setSizes();
269
        // save transparent
270 7
        imagesavealpha($this->getImage(), true);
271 7
        imagealphablending($this->getImage(), false);
272
273 7
        return $this;
274
    }
275
276
    /**
277
     * @param Image $watermark
278
     * @param int $x
279
     * @param int $y
280
     * @return ImageInterface
281
     */
282
    protected function prepareWatermark(Image $watermark, int $x, int $y): ImageInterface
283
    {
284
        imagealphablending($this->getImage(), true);
285
        imagesavealpha($this->getImage(), true);
286
        imagecopyresampled(
287
            $this->getImage(),
288
            $watermark->getImage(),
289
            $x,
290
            $y,
291
            0,
292
            0,
293
            $width = (int)$watermark->getWidth(),
294
            $height = (int)$watermark->getHeight(),
295
            $width,
296
            $height
297
        );
298
299
        return $this;
300
    }
301
}
302