Test Failed
Push — master ( 7f81f1...08fd08 )
by compolom
01:53
created

Imagick2::grayscale()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 3
nc 1
nop 0
dl 0
loc 8
ccs 0
cts 4
cp 0
crap 2
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 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 3
    public function __construct(string $image)
21
    {
22 3
        $this->init($image);
23
    }
24
25
    /**
26
     * @param int $width
27
     * @param int $height
28
     * @return ImageInterface
29
     * @throws ImagickException
30
     */
31
    public function resize(int $width, int $height): ImageInterface
32
    {
33
        $this->getImage()->scaleImage($width, $height, false);
34
        $this->setSizes();
35
36
        return $this;
37
    }
38
39 3
    protected function setSizes(): void
40
    {
41 3
        $args = $this->getImage()->getImageGeometry();
42 3
        $this->setWidth($args['width']);
43 3
        $this->setHeight($args['height']);
44 3
        $this->setOrientation();
45
    }
46
47
    /**
48
     * @param int $angle
49
     * @return ImageInterface
50
     */
51
    public function rotate(int $angle = 90): ImageInterface
52
    {
53
        $this->getImage()->rotateImage(new ImagickPixel('transparent'), $angle);
54
        $this->setSizes();
55
56
        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
    public function getFontsList(): array
120
    {
121
        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
    public function save(string $filename, $quality = 100): bool
175
    {
176
        $this->getImage()->setImageCompressionQuality($quality);
177
        $this->getImage()->setImageFormat('png');
178
        #$this->getImage()->writeImage($filename . '.png'); // bug
179
        file_put_contents ($filename. '.png', $this->getImage());
180
181
        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
    protected function prepareThumbnail(int $width, int $height): ImageInterface
196
    {
197
        $this->getImage()->thumbnailImage($width, $height); //, false, true, true
198
199
        return $this;
200
    }
201
202
    /**
203
     * @param string $source
204
     * @return ImageInterface
205
     * @throws ImagickException
206
     */
207 3
    protected function tmp(string $source): ImageInterface
208
    {
209 3
        $image = new Imagick;
210 3
        if ($image->readImageBlob($source)) {
211 3
            if ($image->getImageAlphaChannel() !== Imagick::ALPHACHANNEL_ACTIVATE) {
212 3
                $image->setImageAlphaChannel(Imagick::ALPHACHANNEL_SET);
213
            }
214
        }
215 3
        $background = $this->newImage($image->getImageWidth(), $image->getImageHeight());
216 3
        $image->compositeImage($background, Imagick::COMPOSITE_OVER, 0, 0); //Imagick::COMPOSITE_DISSOLVE
217 3
        $this->setImage($image);
218 3
        $this->getImage()->setFormat('png'); // save transparent
219 3
        $this->setSizes();
220
221 3
        return $this;
222
    }
223
224
    /**
225
     * @param int $width
226
     * @param int $height
227
     * @return Imagick
228
     * @throws ImagickException
229
     */
230 3
    protected function newImage(int $width, int $height): Imagick
231
    {
232 3
        $background = new Imagick;
233 3
        $background->newImage($width, $height, 'none');
234 3
        $background->setImageAlphaChannel(Imagick::ALPHACHANNEL_TRANSPARENT);
235
236 3
        return $background;
237
    }
238
239
    /**
240
     * @param Image $watermark
241
     * @param int $x
242
     * @param int $y
243
     * @return ImageInterface
244
     * @throws Exception
245
     */
246
    protected function prepareWatermark($watermark, int $x, int $y): ImageInterface
247
    {
248
        $watermark = $watermark->getImage();
249
        $watermark->evaluateImage(Imagick::EVALUATE_MULTIPLY, 1, Imagick::CHANNEL_ALPHA);
250
        $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

250
        $this->getImage()->compositeImage(/** @scrutinizer ignore-type */ $watermark, Imagick::COMPOSITE_DISSOLVE, $x, $y);
Loading history...
251
252
        return $this;
253
    }
254
255
    public function resizeByTransparentBackground(int $width, int $height): ImageInterface
256
    {
257
        $background = $this->newImage($width, $height);
258
        $background->setImageFormat('png');
259
260
        $w = (int) (($width - $this->getWidth()) / 2);
261
        $h = (int) (($height - $this->getHeight()) / 2);
262
263
        $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

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