Imagick2   A
last analyzed

Complexity

Total Complexity 29

Size/Duplication

Total Lines 312
Duplicated Lines 0 %

Test Coverage

Coverage 39.32%

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 105
c 2
b 0
f 0
dl 0
loc 312
ccs 46
cts 117
cp 0.3932
rs 10
wmc 29

23 Methods

Rating   Name   Duplication   Size   Complexity  
A setSizes() 0 6 1
A grayscale() 0 8 1
A __toString() 0 3 1
A copyright() 0 20 3
A __construct() 0 3 1
A crop() 0 9 1
A prepareImage() 0 21 1
A flip() 0 5 1
A flop() 0 5 1
A getFontsList() 0 3 1
A tmp() 0 15 3
A contrast() 0 9 2
A prepareWatermark() 0 7 1
A resizeByBlurBackground() 0 6 1
A resizeByTransparentBackground() 0 11 1
A negate() 0 5 1
A blur() 0 5 1
A newImage() 0 7 1
A brightness() 0 9 2
A prepareThumbnail() 0 6 1
A rotate() 0 6 1
A resize() 0 6 1
A save() 0 8 1
1
<?php declare(strict_types=1);
2
3
namespace Compolomus\Compomage;
4
5
use Compolomus\Compomage\Interfaces\ImageInterface;
6
use Exception;
7
use Imagick;
8
use ImagickDraw;
9
use ImagickException;
10
use ImagickPixel;
11
use InvalidArgumentException;
12
13
class Imagick2 extends AbstractImage
14
{
15
    /**
16
     * Imagick constructor.
17
     * @param string $image
18
     * @throws Exception
19
     */
20 13
    public function __construct(string $image)
21
    {
22 13
        $this->init($image);
23
    }
24
25
    /**
26
     * @param int $width
27
     * @param int $height
28
     * @return ImageInterface
29
     * @throws ImagickException
30
     */
31 1
    public function resize(int $width, int $height): ImageInterface
32
    {
33 1
        $this->getImage()->scaleImage($width, $height, false);
34 1
        $this->setSizes();
35
36 1
        return $this;
37
    }
38
39 13
    protected function setSizes(): void
40
    {
41 13
        $args = $this->getImage()->getImageGeometry();
42 13
        $this->setWidth($args['width']);
43 13
        $this->setHeight($args['height']);
44 13
        $this->setOrientation();
45
    }
46
47
    /**
48
     * @param int $angle
49
     * @return ImageInterface
50
     */
51 1
    public function rotate(int $angle = 90): ImageInterface
52
    {
53 1
        $this->getImage()->rotateImage(new ImagickPixel('transparent'), $angle);
54 1
        $this->setSizes();
55
56 1
        return $this;
57
    }
58
59
    /**
60
     * @return ImageInterface
61
     */
62
    public function flip(): ImageInterface
63
    {
64
        $this->getImage()->flipImage();
65
66
        return $this;
67
    }
68
69
    /**
70
     * @return ImageInterface
71
     */
72
    public function flop(): ImageInterface
73
    {
74
        $this->getImage()->flopImage();
75
76
        return $this;
77
    }
78
79
    public function grayscale(): ImageInterface
80
    {
81
        $this->getImage()->transformimagecolorspace(Imagick::COLORSPACE_GRAY);
82
        $this->getImage()->separateImageChannel(1);
83
84
        // modulateImage(100, 0, 100);
85
86
        return $this;
87
    }
88
89
    /**
90
     * @param string $text
91
     * @param string $position
92
     * @param string $font
93
     * @return ImageInterface
94
     * @throws InvalidArgumentException
95
     * @throws ImagickException
96
     */
97 1
    public function copyright(string $text, string $font = 'Courier', string $position = 'SouthWest'): ImageInterface
98
    {
99 1
        $positions = [
100
            'NORTHWEST' => Imagick::GRAVITY_NORTHWEST,
101
            'NORTH' => Imagick::GRAVITY_NORTH,
102
            'NORTHEAST' => Imagick::GRAVITY_NORTHEAST,
103
            'WEST' => Imagick::GRAVITY_WEST,
104
            'CENTER' => Imagick::GRAVITY_CENTER,
105
            'SOUTHWEST' => Imagick::GRAVITY_SOUTHWEST,
106
            'SOUTH' => Imagick::GRAVITY_SOUTH,
107
            'SOUTHEAST' => Imagick::GRAVITY_SOUTHEAST,
108
            'EAST' => Imagick::GRAVITY_EAST
109
        ];
110 1
        if (!array_key_exists(strtoupper($position), $positions) || !in_array($font, $this->getFontsList(), true)) {
111 1
            throw new InvalidArgumentException('Does not support font or wrong position');
112
        }
113
        $this->getImage()->compositeImage($this->prepareImage($text, $positions[strtoupper($position)], $font),
114
            Imagick::COMPOSITE_DISSOLVE, 0, 0);
115
116
        return $this;
117
    }
118
119 1
    public function getFontsList(): array
120
    {
121 1
        return $this->getImage()->queryFonts();
122
    }
123
124
    /**
125
     * @param string $text
126
     * @param int $position
127
     * @param string $font
128
     * @return Imagick
129
     * @throws ImagickException
130
     */
131
    private function prepareImage(string $text, int $position, string $font): Imagick
132
    {
133
        $image = new Imagick();
134
        $mask = new Imagick();
135
        $draw = new ImagickDraw();
136
        $image->newImage($this->getWidth(), $this->getHeight(), new ImagickPixel('grey30'));
137
        $mask->newImage($this->getWidth(), $this->getHeight(), new ImagickPixel('black'));
138
        $draw->setFont($font);
139
        $draw->setFontSize(20);
140
        $draw->setFillColor(new ImagickPixel('grey70'));
141
        $draw->setGravity($position);
142
        $image->annotateImage($draw, 10, 12, 0, $text);
143
        $draw->setFillColor(new ImagickPixel('white'));
144
        $mask->annotateImage($draw, 11, 13, 0, $text);
145
        $mask->annotateImage($draw, 10, 12, 0, $text);
146
        $draw->setFillColor(new ImagickPixel('black'));
147
        $mask->annotateImage($draw, 9, 11, 0, $text);
148
        $mask->setImageMatte(false);
149
        $image->compositeImage($mask, Imagick::COMPOSITE_COPYOPACITY, 0, 0);
150
151
        return $image;
152
    }
153
154
    /**
155
     * @param int $width
156
     * @param int $height
157
     * @param int $x
158
     * @param int $y
159
     * @return ImageInterface
160
     * @throws ImagickException
161
     */
162
163
    public function crop(int $width, int $height, int $x, int $y): ImageInterface
164
    {
165
        $width -= $x;
166
        $height -= $y;
167
168
        $this->getImage()->cropImage($width, $height, $x, $y);
169
        $this->setSizes();
170
171
        return $this;
172
    }
173
174 1
    public function save(string $filename, $quality = 100): bool
175
    {
176 1
        $this->getImage()->setImageCompressionQuality($quality);
177 1
        $this->getImage()->setImageFormat('png');
178
        #$this->getImage()->writeImage($filename . '.png'); // bug
179 1
        file_put_contents ($filename. '.png', $this->getImage());
180
181 1
        return true;
182
    }
183
184
    public function __toString(): string
185
    {
186
        return trim($this->getImage()->getImageBlob());
187
    }
188
189
    /**
190
     * @param int $width
191
     * @param int $height
192
     * @return ImageInterface
193
     * @throws ImagickException
194
     */
195 1
    protected function prepareThumbnail(int $width, int $height): ImageInterface
196
    {
197 1
        $this->getImage()->thumbnailImage($width, $height); //, false, true, true
198 1
        $this->setSizes();
199
200 1
        return $this;
201
    }
202
203
    /**
204
     * @param string $source
205
     * @return ImageInterface
206
     * @throws ImagickException
207
     */
208 13
    protected function tmp(string $source): ImageInterface
209
    {
210 13
        $image = new Imagick;
211 13
        if ($image->readImageBlob($source)) {
212 13
            if ($image->getImageAlphaChannel() !== Imagick::ALPHACHANNEL_ACTIVATE) {
213 13
                $image->setImageAlphaChannel(Imagick::ALPHACHANNEL_SET);
214
            }
215
        }
216 13
        $background = $this->newImage($image->getImageWidth(), $image->getImageHeight());
217 13
        $image->compositeImage($background, Imagick::COMPOSITE_OVER, 0, 0); //Imagick::COMPOSITE_DISSOLVE
218 13
        $this->setImage($image);
219 13
        $this->getImage()->setFormat('png'); // save transparent
220 13
        $this->setSizes();
221
222 13
        return $this;
223
    }
224
225
    /**
226
     * @param int $width
227
     * @param int $height
228
     * @return Imagick
229
     * @throws ImagickException
230
     */
231 13
    protected function newImage(int $width, int $height): Imagick
232
    {
233 13
        $background = new Imagick;
234 13
        $background->newImage($width, $height, 'none');
235 13
        $background->setImageAlphaChannel(Imagick::ALPHACHANNEL_TRANSPARENT);
236
237 13
        return $background;
238
    }
239
240
    /**
241
     * @param Image $watermark
242
     * @param int $x
243
     * @param int $y
244
     * @return ImageInterface
245
     * @throws Exception
246
     */
247
    protected function prepareWatermark($watermark, int $x, int $y): ImageInterface
248
    {
249
        $watermark = $watermark->getImage();
250
        $watermark->evaluateImage(Imagick::EVALUATE_MULTIPLY, 1, Imagick::CHANNEL_ALPHA);
251
        $this->getImage()->compositeImage($watermark, Imagick::COMPOSITE_DISSOLVE, $x, $y);
0 ignored issues
show
Bug introduced by
$watermark of type Compolomus\Compomage\Image is incompatible with the type Imagick expected by parameter $composite_object of Imagick::compositeImage(). ( Ignorable by Annotation )

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

251
        $this->getImage()->compositeImage(/** @scrutinizer ignore-type */ $watermark, Imagick::COMPOSITE_DISSOLVE, $x, $y);
Loading history...
252
253
        return $this;
254
    }
255
256
    public function resizeByTransparentBackground(int $width, int $height): ImageInterface
257
    {
258
        $background = $this->newImage($width, $height);
259
        $background->setImageFormat('png');
260
261
        $w = (int) (($width - $this->getWidth()) / 2);
262
        $h = (int) (($height - $this->getHeight()) / 2);
263
264
        $background->compositeImage($this->getImage(), Imagick::COMPOSITE_DISSOLVE, $w, $h);
0 ignored issues
show
Bug introduced by
It seems like $this->getImage() can also be of type resource; however, parameter $composite_object of Imagick::compositeImage() does only seem to accept Imagick, 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

264
        $background->compositeImage(/** @scrutinizer ignore-type */ $this->getImage(), Imagick::COMPOSITE_DISSOLVE, $w, $h);
Loading history...
265
266
        return $this->setBackground($width, $height, new Image(base64_encode((string) $background), Image::IMAGICK));
267
    }
268
269
    public function resizeByBlurBackground(int $width, int $height): ImageInterface
270
    {
271
        $background = new Image(base64_encode((string) $this));
272
        $background->resize($width, $height)->blur();
273
274
        return $this->setBackground($width, $height, $background);
275
    }
276
277
    /**
278
     * @param int $level
279
     * @return ImageInterface
280
     */
281
    public function brightness(int $level): ImageInterface
282
    {
283
        if (!$this->compareRangeValue($level, 200))
284
        {
285
            throw new InvalidArgumentException('Wrong brightness level, range 0 - 200, ' . $level . ' given');
286
        }
287
        $this->getImage()->modulateImage(abs($level), 100, 100);
288
289
        return $this;
290
    }
291
292
    /**
293
     * @param int $level
294
     * @return ImageInterface
295
     */
296
    public function contrast(int $level): ImageInterface
297
    {
298
        if (!$this->compareRangeValue($level, 100))
299
        {
300
            throw new InvalidArgumentException('Wrong contrast level, range 0 - 100, ' . $level . ' given');
301
        }
302
        $this->getImage()->brightnessContrastImage(0, abs($level));
303
304
        return $this;
305
    }
306
307
    /**
308
     * @return ImageInterface
309
     */
310
    public function negate(): ImageInterface
311
    {
312
        $this->getImage()->negateImage(false);
313
314
        return $this;
315
    }
316
317
    /**
318
     * @return ImageInterface
319
     */
320
    public function blur(): ImageInterface
321
    {
322
        $this->getImage()->blurImage(7, 5);
323
324
        return $this;
325
    }
326
}
327