Completed
Push — master ( 80eb51...d7d63e )
by Oscar
7s
created

Imagick::watermark()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 4
rs 10
cc 1
eloc 2
nc 1
nop 3
1
<?php
2
3
namespace Imagecow\Libs;
4
5
use Imagick as BaseImagick;
6
use Imagecow\ImageException;
7
use Imagecow\Utils;
8
9
/**
10
 * Imagick library.
11
 */
12
class Imagick extends AbstractLib implements LibInterface
13
{
14
    protected $image;
15
16
    /**
17
     * {@inheritdoc}
18
     */
19
    public static function checkCompatibility()
20
    {
21
        return extension_loaded('imagick');
22
    }
23
24
    /**
25
     * {@inheritdoc}
26
     *
27
     * @return Imagick
28
     */
29
    public static function createFromFile($filename)
30
    {
31
        $imagick = new BaseImagick();
32
33
        if ($imagick->readImage($filename) !== true) {
34
            throw new ImageException("The image file '{$filename}' cannot be loaded");
35
        }
36
37
        return new static($imagick);
38
    }
39
40
    /**
41
     * {@inheritdoc}
42
     *
43
     * @return Imagick
44
     */
45
    public static function createFromString($string)
46
    {
47
        $imagick = new BaseImagick();
48
49
        $imagick->readImageBlob($string);
50
51
        return new static($imagick);
52
    }
53
54
    /**
55
     * Constructor of the class.
56
     *
57
     * @param BaseImagick $image The Imagick instance
58
     */
59
    public function __construct(BaseImagick $image)
60
    {
61
        $this->image = $image;
62
63
        //Convert CMYK to RGB
64
        if ($this->image->getImageColorspace() !== BaseImagick::COLORSPACE_CMYK) {
65
            return $this;
0 ignored issues
show
Bug introduced by
Constructors do not have meaningful return values, anything that is returned from here is discarded. Are you sure this is correct?
Loading history...
66
        }
67
68
        $profiles = $this->image->getImageProfiles('*', false);
69
70
        if (array_search('icc', $profiles) === false) {
71
            $this->image->profileImage('icc', file_get_contents(__DIR__.'/icc/us_web_uncoated.icc'));
72
        }
73
74
        $this->image->profileImage('icm', file_get_contents(__DIR__.'/icc/srgb.icm'));
75
        $this->image->transformImageColorspace(BaseImagick::COLORSPACE_SRGB);
76
    }
77
78
    /**
79
     * Destroy the image.
80
     */
81
    public function __destruct()
82
    {
83
        $this->image->destroy();
84
    }
85
86
    /**
87
     * {@inheritdoc}
88
     */
89
    public function flip()
90
    {
91
        if ($this->image->flipImage() !== true) {
92
            throw new ImageException('There was an error on flip the image');
93
        }
94
    }
95
96
    /**
97
     * {@inheritdoc}
98
     */
99
    public function flop()
100
    {
101
        if ($this->image->flopImage() !== true) {
102
            throw new ImageException('There was an error on flop the image');
103
        }
104
    }
105
106
    /**
107
     * {@inheritdoc}
108
     */
109
    public function save($filename)
110
    {
111
        $image = $this->getCompressed();
112
113
        if ($this->animated) {
114
            if (!($fp = fopen($filename, 'w'))) {
115
                throw new ImageException("The image file '{$filename}' cannot be saved");
116
            }
117
118
            $image->writeImagesFile($fp);
119
120
            fclose($fp);
121
        } elseif (!$image->writeImage($filename)) {
122
            throw new ImageException("The image file '{$filename}' cannot be saved");
123
        }
124
    }
125
126
    /**
127
     * Gets the original image object.
128
     *
129
     * @return object
130
     */
131
    public function getImage()
132
    {
133
        return $this->image;
134
    }
135
136
    /**
137
     * {@inheritdoc}
138
     */
139
    public function getString()
140
    {
141
        $image = $this->getCompressed();
142
143
        if (!$this->animated) {
144
            return $image->getImageBlob();
145
        }
146
147
        if (!($fp = fopen($file = tempnam(sys_get_temp_dir(), 'imagick'), 'w'))) {
148
            throw new ImageException('Cannot create a temp file to generate the string data image');
149
        }
150
151
        $image->writeImagesFile($fp);
152
153
        fclose($fp);
154
155
        $string = file_get_contents($file);
156
157
        unlink($file);
158
159
        return $string;
160
    }
161
162
    /**
163
     * {@inheritdoc}
164
     */
165
    public function getMimeType()
166
    {
167
        $format = strtolower($this->image->getImageFormat());
168
169
        if (in_array($format, ['jpeg', 'jpg', 'gif', 'png'], true)) {
170
            return "image/$format";
171
        }
172
    }
173
174
    /**
175
     * {@inheritdoc}
176
     */
177
    public function getWidth()
178
    {
179
        return $this->image->getImageWidth();
180
    }
181
182
    /**
183
     * {@inheritdoc}
184
     */
185
    public function getHeight()
186
    {
187
        return $this->image->getImageHeight();
188
    }
189
190
    /**
191
     * {@inheritdoc}
192
     */
193
    public function format($format)
194
    {
195
        if (preg_match('/jpe?g/i', $format)) {
196
            list($r, $g, $b) = $this->background;
197
198
            $this->image->setImageBackgroundColor("rgb($r,$g,$b)");
199
            $this->image = $this->image->mergeImageLayers(BaseImagick::LAYERMETHOD_FLATTEN);
200
        }
201
202
        if ($this->image->setImageFormat($format) !== true) {
203
            throw new ImageException("The image format '{$format}' is not valid");
204
        }
205
    }
206
207
    /**
208
     * {@inheritdoc}
209
     */
210
    public function resize($width, $height)
211
    {
212
        if ($this->animated) {
213
            $this->image = $this->image->coalesceImages();
214
215
            foreach ($this->image as $frame) {
216
                $frame->scaleImage($width, $height);
217
            }
218
219
            $this->image = $this->image->deconstructImages();
220 View Code Duplication
        } else {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
221
            if ($this->image->scaleImage($width, $height) !== true) {
222
                throw new ImageException('There was an error resizing the image');
223
            }
224
225
            $this->image->setImagePage(0, 0, 0, 0);
226
        }
227
    }
228
229
    /**
230
     * {@inheritdoc}
231
     */
232
    public function getCropOffsets($width, $height, $method)
233
    {
234
        $class = 'Imagecow\\Crops\\'.ucfirst(strtolower($method));
235
236
        if (!class_exists($class)) {
237
            throw new ImageException("The crop method '$method' is not available for Imagick");
238
        }
239
240
        return $class::getOffsets($this->image, $width, $height);
241
    }
242
243
    /**
244
     * {@inheritdoc}
245
     */
246
    public function crop($width, $height, $x, $y)
247
    {
248
        if ($this->animated) {
249
            $this->image = $this->image->coalesceImages();
250
251
            foreach ($this->image as $frame) {
252
                $frame->cropImage($width, $height, $x, $y);
253
                $frame->setImagePage(0, 0, 0, 0);
254
            }
255
256
            $this->image = $this->image->deconstructImages();
257 View Code Duplication
        } else {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
258
            if ($this->image->cropImage($width, $height, $x, $y) !== true) {
259
                throw new ImageException('There was an error cropping the image');
260
            }
261
262
            $this->image->setImagePage(0, 0, 0, 0);
263
        }
264
    }
265
266
    /**
267
     * {@inheritdoc}
268
     */
269
    public function rotate($angle)
270
    {
271
        if ($this->image->rotateImage(new BaseImagickPixel(), $angle) !== true) {
272
            throw new ImageException('There was an error rotating the image');
273
        }
274
275
        $this->image->setImagePage(0, 0, 0, 0);
276
    }
277
278
    /**
279
     * Returns a copy of the image compressed and ready to save or print.
280
     *
281
     * @return BaseImagick The instance of the image
282
     */
283
    private function getCompressed()
284
    {
285
        $image = $this->image;
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->image; of type Imagick|boolean adds the type boolean to the return on line 320 which is incompatible with the return type documented by Imagecow\Libs\Imagick::getCompressed of type Imagick.
Loading history...
286
287
        if ($this->animated) {
288
            $image = $image->coalesceImages();
289
290
            foreach ($image as $frame) {
291
                $frame->stripImage();
292
                $frame->setImageUnits(1);
293
                $frame->setImageCompressionQuality($this->quality);
294
            }
295
296
            return $image->deconstructImages();
297
        }
298
299
        $format = strtolower($image->getImageFormat());
300
301
        $image->stripImage();
302
        $image->setImageUnits(1);
303
        $image->setImageCompressionQuality($this->quality);
304
305
        switch ($format) {
306
            case 'jpeg':
307
                $image->setInterlaceScheme(BaseImagick::INTERLACE_JPEG);
308
                $image->setImageCompression(BaseImagick::COMPRESSION_JPEG);
309
                break;
310
311
            case 'gif':
312
                $image->setInterlaceScheme(BaseImagick::INTERLACE_GIF);
313
                break;
314
315
            case 'png':
316
                $image->setInterlaceScheme(BaseImagick::INTERLACE_PNG);
317
                break;
318
        }
319
320
        return $image;
321
    }
322
323
    /**
324
     * @param object $watermark Watermark image object
325
     * @param array  $x         Position x
326
     * @param array  $y         Position y
327
     */
328
    public function watermark($watermark, $x, $y)
329
    {
330
        $this->image->compositeImage($watermark, BaseImagick::COMPOSITE_DISSOLVE, $x, $y);
331
    }
332
333
    /**
334
     * {@inheritdoc}
335
     */
336
    public function opacity($opacity)
337
    {
338
        if ($opacity === 100) {
339
            return;
340
        }
341
342
        if ($this->image->getImageAlphaChannel() !== BaseImagick::ALPHACHANNEL_ACTIVATE) {
343
            $this->image->setImageAlphaChannel(BaseImagick::ALPHACHANNEL_OPAQUE);
344
        }
345
346
        // NOTE: Using setImageOpacity will destroy current alpha channels!
347
        $this->image->evaluateImage(BaseImagick::EVALUATE_MULTIPLY, $opacity / 100, BaseImagick::CHANNEL_ALPHA);
348
    }
349
}
350