Image_Imagick   A
last analyzed

Complexity

Total Complexity 39

Size/Duplication

Total Lines 348
Duplicated Lines 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
eloc 125
dl 0
loc 348
rs 9.28
c 3
b 0
f 0
wmc 39

15 Methods

Rating   Name   Duplication   Size   Complexity  
A _do_render() 0 16 1
A _do_adapt() 0 10 1
A _do_save() 0 24 2
A _do_crop() 0 14 2
A check() 0 7 2
A _do_sharpen() 0 9 2
A _do_resize() 0 11 2
A __construct() 0 27 6
A _get_imagetype() 0 22 5
A __destruct() 0 4 1
A _do_reflection() 0 52 4
A _do_watermark() 0 21 4
A _do_flip() 0 6 2
A _do_background() 0 28 3
A _do_rotate() 0 14 2
1
<?php
2
3
namespace image\components\drivers;
4
5
use image\components\Kohana\Image;
6
use yii\base\ErrorException;
7
use \Imagick;
8
use \ImagickPixel;
9
10
/**
11
 * Support for image manipulation using [Imagick](http://php.net/Imagick).
12
 *
13
 * @package    image\components\drivers
14
 * @category   Drivers
15
 * @author     Tamas Mihalik [email protected]
16
 * @copyright  (c) 2009-2012,2018 Kohana Team
17
 * @license    http://kohanaphp.com/license.html
18
 */
19
class Image_Imagick extends Image implements DriverInterface
20
{
21
22
    /**
23
     * @var  Imagick  image magick object
24
     */
25
    protected $im;
26
27
    /**
28
     * Checks if ImageMagick is enabled.
29
     *
30
     * @throws  ErrorException
31
     * @return  boolean
32
     */
33
    public static function check()
34
    {
35
        if (!extension_loaded('imagick')) {
36
            throw new ErrorException('Imagick is not installed, or the extension is not loaded');
37
        }
38
39
        return Image_Imagick::$_checked = true;
40
    }
41
42
    /**
43
     * Runs [Image_Imagick::check] and loads the image.
44
     *
45
     * @return  void
46
     * @param $file
47
     * @throws ErrorException
48
     * @throws \ImagickException
49
     */
50
    public function __construct($file)
51
    {
52
        if (!Image_Imagick::$_checked) {
53
            // Run the install check
54
            Image_Imagick::check();
55
        }
56
57
        parent::__construct($file);
58
59
        $this->im = new Imagick;
60
        $this->im->readImage($file);
61
62
        // Force RGB colorspace if we are using non-RGB
63
        $imageColorspace = $this->im->getImageColorspace();
64
        if ($imageColorspace !== Imagick::COLORSPACE_RGB &&
65
            $imageColorspace !== Imagick::COLORSPACE_SRGB
66
        ) {
67
            $imageColorspace = Imagick::COLORSPACE_RGB;
68
        }
69
        if ($this->im->getImageColorspace() !== $imageColorspace) {
70
            $this->im->transformImageColorspace($imageColorspace);
71
        }
72
        $this->im->setColorspace($imageColorspace);
73
74
        if (!$this->im->getImageAlphaChannel()) {
75
            // Force the image to have an alpha channel
76
            $this->im->setImageAlphaChannel(Imagick::ALPHACHANNEL_SET);
77
        }
78
    }
79
80
    /**
81
     * Destroys the loaded image to free up resources.
82
     *
83
     * @return  void
84
     */
85
    public function __destruct()
86
    {
87
        $this->im->clear();
88
        $this->im->destroy();
89
    }
90
91
    public function _do_resize($width, $height)
92
    {
93
        if ($this->im->scaleImage($width, $height)) {
94
            // Reset the width and height
95
            $this->width = $this->im->getImageWidth();
96
            $this->height = $this->im->getImageHeight();
97
98
            return true;
0 ignored issues
show
Bug Best Practice introduced by
The expression return true returns the type true which is incompatible with the return type mandated by image\components\drivers...Interface::_do_resize() of void.

In the issue above, the returned value is violating the contract defined by the mentioned interface.

Let's take a look at an example:

interface HasName {
    /** @return string */
    public function getName();
}

class Name {
    public $name;
}

class User implements HasName {
    /** @return string|Name */
    public function getName() {
        return new Name('foo'); // This is a violation of the ``HasName`` interface
                                // which only allows a string value to be returned.
    }
}
Loading history...
99
        }
100
101
        return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the return type mandated by image\components\drivers...Interface::_do_resize() of void.

In the issue above, the returned value is violating the contract defined by the mentioned interface.

Let's take a look at an example:

interface HasName {
    /** @return string */
    public function getName();
}

class Name {
    public $name;
}

class User implements HasName {
    /** @return string|Name */
    public function getName() {
        return new Name('foo'); // This is a violation of the ``HasName`` interface
                                // which only allows a string value to be returned.
    }
}
Loading history...
102
    }
103
104
    /**
105
     * Adaptation the image.
106
     *
107
     * @param   integer $width image width
108
     * @param   integer $height image height
109
     * @param   integer $bg_width background width
110
     * @param   integer $bg_height background height
111
     * @param   integer $offset_x offset from the left
112
     * @param   integer $offset_y offset from the top
113
     * @throws \ImagickException
114
     */
115
    public function _do_adapt($width, $height, $bg_width, $bg_height, $offset_x, $offset_y)
116
    {
117
        $image = new Imagick();
118
        $image->newImage($bg_width, $bg_height, "none");
119
        $image->compositeImage($this->im, Imagick::COMPOSITE_ADD, $offset_x, $offset_y);
120
        $this->im->clear();
121
        $this->im->destroy();
122
        $this->im = $image;
123
        $this->width = $bg_width;
124
        $this->height = $bg_height;
125
    }
126
127
    public function _do_crop($width, $height, $offset_x, $offset_y)
128
    {
129
        if ($this->im->cropImage($width, $height, $offset_x, $offset_y)) {
130
            // Reset the width and height
131
            $this->width = $this->im->getImageWidth();
132
            $this->height = $this->im->getImageHeight();
133
134
            // Trim off hidden areas
135
            $this->im->setImagePage($this->width, $this->height, 0, 0);
136
137
            return true;
0 ignored issues
show
Bug Best Practice introduced by
The expression return true returns the type true which is incompatible with the return type mandated by image\components\drivers...erInterface::_do_crop() of void.

In the issue above, the returned value is violating the contract defined by the mentioned interface.

Let's take a look at an example:

interface HasName {
    /** @return string */
    public function getName();
}

class Name {
    public $name;
}

class User implements HasName {
    /** @return string|Name */
    public function getName() {
        return new Name('foo'); // This is a violation of the ``HasName`` interface
                                // which only allows a string value to be returned.
    }
}
Loading history...
138
        }
139
140
        return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the return type mandated by image\components\drivers...erInterface::_do_crop() of void.

In the issue above, the returned value is violating the contract defined by the mentioned interface.

Let's take a look at an example:

interface HasName {
    /** @return string */
    public function getName();
}

class Name {
    public $name;
}

class User implements HasName {
    /** @return string|Name */
    public function getName() {
        return new Name('foo'); // This is a violation of the ``HasName`` interface
                                // which only allows a string value to be returned.
    }
}
Loading history...
141
    }
142
143
    public function _do_rotate($degrees)
144
    {
145
        if ($this->im->rotateImage(new ImagickPixel('transparent'), $degrees)) {
146
            // Reset the width and height
147
            $this->width = $this->im->getImageWidth();
148
            $this->height = $this->im->getImageHeight();
149
150
            // Trim off hidden areas
151
            $this->im->setImagePage($this->width, $this->height, 0, 0);
152
153
            return true;
0 ignored issues
show
Bug Best Practice introduced by
The expression return true returns the type true which is incompatible with the return type mandated by image\components\drivers...Interface::_do_rotate() of void.

In the issue above, the returned value is violating the contract defined by the mentioned interface.

Let's take a look at an example:

interface HasName {
    /** @return string */
    public function getName();
}

class Name {
    public $name;
}

class User implements HasName {
    /** @return string|Name */
    public function getName() {
        return new Name('foo'); // This is a violation of the ``HasName`` interface
                                // which only allows a string value to be returned.
    }
}
Loading history...
154
        }
155
156
        return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the return type mandated by image\components\drivers...Interface::_do_rotate() of void.

In the issue above, the returned value is violating the contract defined by the mentioned interface.

Let's take a look at an example:

interface HasName {
    /** @return string */
    public function getName();
}

class Name {
    public $name;
}

class User implements HasName {
    /** @return string|Name */
    public function getName() {
        return new Name('foo'); // This is a violation of the ``HasName`` interface
                                // which only allows a string value to be returned.
    }
}
Loading history...
157
    }
158
159
    public function _do_flip($direction)
160
    {
161
        if ($direction === Image::HORIZONTAL) {
162
            return $this->im->flopImage();
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->im->flopImage() returns the type boolean which is incompatible with the return type mandated by image\components\drivers...erInterface::_do_flip() of void.

In the issue above, the returned value is violating the contract defined by the mentioned interface.

Let's take a look at an example:

interface HasName {
    /** @return string */
    public function getName();
}

class Name {
    public $name;
}

class User implements HasName {
    /** @return string|Name */
    public function getName() {
        return new Name('foo'); // This is a violation of the ``HasName`` interface
                                // which only allows a string value to be returned.
    }
}
Loading history...
163
        } else {
164
            return $this->im->flipImage();
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->im->flipImage() returns the type boolean which is incompatible with the return type mandated by image\components\drivers...erInterface::_do_flip() of void.

In the issue above, the returned value is violating the contract defined by the mentioned interface.

Let's take a look at an example:

interface HasName {
    /** @return string */
    public function getName();
}

class Name {
    public $name;
}

class User implements HasName {
    /** @return string|Name */
    public function getName() {
        return new Name('foo'); // This is a violation of the ``HasName`` interface
                                // which only allows a string value to be returned.
    }
}
Loading history...
165
        }
166
    }
167
168
    public function _do_sharpen($amount)
169
    {
170
        // IM not support $amount under 5 (0.15)
171
        $amount = ($amount < 5) ? 5 : $amount;
172
173
        // Amount should be in the range of 0.0 to 3.0
174
        $amount = ($amount * 3.0) / 100;
175
176
        return $this->im->sharpenImage(0, $amount);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->im->sharpenImage(0, $amount) returns the type boolean which is incompatible with the return type mandated by image\components\drivers...nterface::_do_sharpen() of void.

In the issue above, the returned value is violating the contract defined by the mentioned interface.

Let's take a look at an example:

interface HasName {
    /** @return string */
    public function getName();
}

class Name {
    public $name;
}

class User implements HasName {
    /** @return string|Name */
    public function getName() {
        return new Name('foo'); // This is a violation of the ``HasName`` interface
                                // which only allows a string value to be returned.
    }
}
Loading history...
177
    }
178
179
    public function _do_reflection($height, $opacity, $fade_in)
180
    {
181
        // Clone the current image and flip it for reflection
182
        $reflection = $this->im->clone();
183
        $reflection->flipImage();
184
185
        // Crop the reflection to the selected height
186
        $reflection->cropImage($this->width, $height, 0, 0);
187
        $reflection->setImagePage($this->width, $height, 0, 0);
188
189
        // Select the fade direction
190
        $direction = array('transparent', 'black');
191
192
        if ($fade_in) {
193
            // Change the direction of the fade
194
            $direction = array_reverse($direction);
195
        }
196
197
        // Create a gradient for fading
198
        $fade = new Imagick;
199
        $fade->newPseudoImage($reflection->getImageWidth(), $reflection->getImageHeight(), vsprintf('gradient:%s-%s', $direction));
200
201
        // Apply the fade alpha channel to the reflection
202
        $reflection->compositeImage($fade, Imagick::COMPOSITE_DSTOUT, 0, 0);
203
204
        // NOTE: Using setImageOpacity will destroy alpha channels!
205
        $reflection->evaluateImage(Imagick::EVALUATE_MULTIPLY, $opacity / 100, Imagick::CHANNEL_ALPHA);
206
207
        // Create a new container to hold the image and reflection
208
        $image = new Imagick;
209
        $image->newImage($this->width, $this->height + $height, new ImagickPixel);
210
211
        // Force the image to have an alpha channel
212
        $image->setImageAlphaChannel(Imagick::ALPHACHANNEL_SET);
213
214
        // Force the background color to be transparent
215
        // $image->setImageBackgroundColor(new ImagickPixel('transparent'));
216
217
        // Place the image and reflection into the container
218
        if ($image->compositeImage($this->im, Imagick::COMPOSITE_SRC, 0, 0)
219
            && $image->compositeImage($reflection, Imagick::COMPOSITE_OVER, 0, $this->height)) {
220
            // Replace the current image with the reflected image
221
            $this->im = $image;
222
223
            // Reset the width and height
224
            $this->width = $this->im->getImageWidth();
225
            $this->height = $this->im->getImageHeight();
226
227
            return true;
0 ignored issues
show
Bug Best Practice introduced by
The expression return true returns the type true which is incompatible with the return type mandated by image\components\drivers...rface::_do_reflection() of void.

In the issue above, the returned value is violating the contract defined by the mentioned interface.

Let's take a look at an example:

interface HasName {
    /** @return string */
    public function getName();
}

class Name {
    public $name;
}

class User implements HasName {
    /** @return string|Name */
    public function getName() {
        return new Name('foo'); // This is a violation of the ``HasName`` interface
                                // which only allows a string value to be returned.
    }
}
Loading history...
228
        }
229
230
        return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the return type mandated by image\components\drivers...rface::_do_reflection() of void.

In the issue above, the returned value is violating the contract defined by the mentioned interface.

Let's take a look at an example:

interface HasName {
    /** @return string */
    public function getName();
}

class Name {
    public $name;
}

class User implements HasName {
    /** @return string|Name */
    public function getName() {
        return new Name('foo'); // This is a violation of the ``HasName`` interface
                                // which only allows a string value to be returned.
    }
}
Loading history...
231
    }
232
233
    /**
234
     * @param \image\components\Kohana\Image $image
235
     * @param int $offset_x
236
     * @param int $offset_y
237
     * @param int $opacity
238
     * @return bool
239
     * @throws \ImagickException
240
     */
241
    public function _do_watermark(\image\components\Kohana\Image $image, $offset_x, $offset_y, $opacity)
242
    {
243
        // Convert the Image intance into an Imagick instance
244
        $watermark = new Imagick;
245
        $watermark->readImageBlob($image->render(), $image->file);
246
        if ($this->im->getImageColorspace() !== $this->im->getColorspace()) {
247
            $watermark->transformImageColorspace($this->im->getColorspace());
248
        }
249
250
        if ($watermark->getImageAlphaChannel() !== Imagick::ALPHACHANNEL_ACTIVATE) {
251
            // Force the image to have an alpha channel
252
            $watermark->setImageAlphaChannel(Imagick::ALPHACHANNEL_OPAQUE);
253
        }
254
255
        if ($opacity < 100) {
256
            // NOTE: Using setImageOpacity will destroy current alpha channels!
257
            $watermark->evaluateImage(Imagick::EVALUATE_MULTIPLY, $opacity / 100, Imagick::CHANNEL_ALPHA);
258
        }
259
260
        // Apply the watermark to the image
261
        return $this->im->compositeImage($watermark, Imagick::COMPOSITE_DISSOLVE, $offset_x, $offset_y);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->im->compos..., $offset_x, $offset_y) returns the type boolean which is incompatible with the return type mandated by image\components\drivers...erface::_do_watermark() of void.

In the issue above, the returned value is violating the contract defined by the mentioned interface.

Let's take a look at an example:

interface HasName {
    /** @return string */
    public function getName();
}

class Name {
    public $name;
}

class User implements HasName {
    /** @return string|Name */
    public function getName() {
        return new Name('foo'); // This is a violation of the ``HasName`` interface
                                // which only allows a string value to be returned.
    }
}
Loading history...
262
    }
263
264
    public function _do_background($r, $g, $b, $opacity)
265
    {
266
        // Create a RGB color for the background
267
        $color = sprintf('rgb(%d, %d, %d)', $r, $g, $b);
268
269
        // Create a new image for the background
270
        $background = new Imagick;
271
        $background->newImage($this->width, $this->height, new ImagickPixel($color));
272
273
        if (!$background->getImageAlphaChannel()) {
274
            // Force the image to have an alpha channel
275
            $background->setImageAlphaChannel(Imagick::ALPHACHANNEL_SET);
276
        }
277
278
        // Clear the background image
279
        $background->setImageBackgroundColor(new ImagickPixel('transparent'));
280
281
        // NOTE: Using setImageOpacity will destroy current alpha channels!
282
        $background->evaluateImage(Imagick::EVALUATE_MULTIPLY, $opacity / 100, Imagick::CHANNEL_ALPHA);
283
284
        if ($background->compositeImage($this->im, Imagick::COMPOSITE_DISSOLVE, 0, 0)) {
285
            // Replace the current image with the new image
286
            $this->im = $background;
287
288
            return true;
0 ignored issues
show
Bug Best Practice introduced by
The expression return true returns the type true which is incompatible with the return type mandated by image\components\drivers...rface::_do_background() of void.

In the issue above, the returned value is violating the contract defined by the mentioned interface.

Let's take a look at an example:

interface HasName {
    /** @return string */
    public function getName();
}

class Name {
    public $name;
}

class User implements HasName {
    /** @return string|Name */
    public function getName() {
        return new Name('foo'); // This is a violation of the ``HasName`` interface
                                // which only allows a string value to be returned.
    }
}
Loading history...
289
        }
290
291
        return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the return type mandated by image\components\drivers...rface::_do_background() of void.

In the issue above, the returned value is violating the contract defined by the mentioned interface.

Let's take a look at an example:

interface HasName {
    /** @return string */
    public function getName();
}

class Name {
    public $name;
}

class User implements HasName {
    /** @return string|Name */
    public function getName() {
        return new Name('foo'); // This is a violation of the ``HasName`` interface
                                // which only allows a string value to be returned.
    }
}
Loading history...
292
    }
293
294
    public function _do_save($file, $quality)
295
    {
296
        // Get the image format and type
297
        list($format, $type) = $this->_get_imagetype(pathinfo($file, PATHINFO_EXTENSION));
298
299
        // Set the output image type
300
        $this->im->setFormat($format);
301
302
        // Set the output quality
303
        $this->im->setImageCompressionQuality($quality);
304
305
        // Sets the image compression
306
        // progressive jpeg
307
        $this->im->setInterlaceScheme(Imagick::INTERLACE_PLANE);
308
309
        if ($this->im->writeImage($file)) {
310
            // Reset the image type and mime type
311
            $this->type = $type;
312
            $this->mime = image_type_to_mime_type($type);
313
314
            return true;
315
        }
316
317
        return false;
318
    }
319
320
    public function _do_render($type, $quality)
321
    {
322
        // Get the image format and type
323
        list($format, $type) = $this->_get_imagetype($type);
324
325
        // Set the output image type
326
        $this->im->setFormat($format);
327
328
        // Set the output quality
329
        $this->im->setImageCompressionQuality($quality);
330
331
        // Reset the image type and mime type
332
        $this->type = $type;
333
        $this->mime = image_type_to_mime_type($type);
334
335
        return (string)$this->im;
336
    }
337
338
    /**
339
     * Get the image type and format for an extension.
340
     *
341
     * @param   string $extension image extension: png, jpg, etc
342
     * @return  array  IMAGETYPE_* constant
343
     * @throws  ErrorException
344
     */
345
    public function _get_imagetype($extension)
346
    {
347
        // Normalize the extension to a format
348
        $format = strtolower($extension);
349
350
        switch ($format) {
351
            case 'jpg':
352
            case 'jpeg':
353
                $type = IMAGETYPE_JPEG;
354
                break;
355
            case 'gif':
356
                $type = IMAGETYPE_GIF;
357
                break;
358
            case 'png':
359
                $type = IMAGETYPE_PNG;
360
                break;
361
            default:
362
                throw new ErrorException(sprintf('Installed ImageMagick does not support %s images', $extension));
363
                break;
364
        }
365
366
        return [$format, $type];
367
    }
368
} // End Kohana_Image_Imagick
369