Completed
Push — master ( b8ff02...c03169 )
by Oscar
01:11
created

Gd::blur()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 19
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 19
rs 9.4285
cc 3
eloc 11
nc 3
nop 1
1
<?php
2
3
namespace Imagecow\Libs;
4
5
use Imagecow\ImageException;
6
7
/**
8
 * GD library.
9
 */
10
class Gd extends AbstractLib implements LibInterface
11
{
12
    public static $fallbackCropMethods = [
13
        'Entropy' => ['center', 'middle'],
14
        'Balanced' => ['center', 'middle'],
15
    ];
16
17
    protected $image;
18
    protected $type;
19
20
    /**
21
     * {@inheritdoc}
22
     */
23
    public static function checkCompatibility()
24
    {
25
        return extension_loaded('gd');
26
    }
27
28
    /**
29
     * {@inheritdoc}
30
     */
31
    public static function createFromFile($filename)
32
    {
33
        $data = getImageSize($filename);
34
35
        if (empty($data) || !is_array($data)) {
36
            throw new ImageException("The image file '{$filename}' cannot be loaded");
37
        }
38
39
        $function = 'imagecreatefrom'.image_type_to_extension($data[2], false);
40
41
        if (function_exists($function)) {
42
            return new static($function($filename), $data[2]);
43
        }
44
    }
45
46
    /**
47
     * {@inheritdoc}
48
     */
49
    public static function createFromString($string)
50
    {
51
        if (($image = imagecreatefromstring($string))) {
52
            return new static($image);
53
        }
54
55
        throw new ImageException('Error creating the image from string');
56
    }
57
58
    /**
59
     * Constructor of the class.
60
     *
61
     * @param resource $image The Gd resource.
62
     */
63
    public function __construct($image, $type = null)
64
    {
65
        $this->image = $image;
66
        $this->type = isset($type) ? $type : IMAGETYPE_PNG;
67
68
        imagealphablending($this->image, true);
69
        imagesavealpha($this->image, true);
70
        imagesetinterpolation($this->image, IMG_BICUBIC);
71
    }
72
73
    /**
74
     * Destroy the image.
75
     */
76
    public function __destruct()
77
    {
78
        imagedestroy($this->image);
79
    }
80
81
    /**
82
     * {@inheritdoc}
83
     */
84
    public function flip()
85
    {
86
        imageflip($this->image, IMG_FLIP_VERTICAL);
87
    }
88
89
    /**
90
     * {@inheritdoc}
91
     */
92
    public function flop()
93
    {
94
        imageflip($this->image, IMG_FLIP_HORIZONTAL);
95
    }
96
97
    /**
98
     * {@inheritdoc}
99
     */
100
    public function save($filename)
101
    {
102
        $extension = image_type_to_extension($this->type, false);
103
        $function = 'image'.$extension;
104
105
        if (!function_exists($function) || ($function($this->image, $filename) === false)) {
106
            throw new ImageException("The image format '{$extension}' cannot be saved to '{$filename}'");
107
        }
108
    }
109
110
    /**
111
     * Gets the original image object.
112
     *
113
     * @return resource
114
     */
115
    public function getImage()
116
    {
117
        return $this->image;
118
    }
119
120
    /**
121
     * {@inheritdoc}
122
     */
123
    public function getString()
124
    {
125
        $extension = image_type_to_extension($this->type, false);
126
        $function = 'image'.$extension;
127
128
        if (!function_exists($function)) {
129
            throw new ImageException("The image format '{$extension}' cannot be exported");
130
        }
131
132
        ob_start();
133
134
        if ($extension === 'jpeg') {
135
            $function($this->image, null, $this->quality);
136
        } else {
137
            $function($this->image);
138
        }
139
140
        return ob_get_clean();
141
    }
142
143
    /**
144
     * {@inheritdoc}
145
     */
146
    public function getMimeType()
147
    {
148
        return image_type_to_mime_type($this->type);
149
    }
150
151
    /**
152
     * {@inheritdoc}
153
     */
154
    public function getWidth()
155
    {
156
        return imagesx($this->image);
157
    }
158
159
    /**
160
     * {@inheritdoc}
161
     */
162
    public function getHeight()
163
    {
164
        return imagesy($this->image);
165
    }
166
167
    /**
168
     * {@inheritdoc}
169
     */
170
    public function format($format)
171
    {
172
        switch (strtolower($format)) {
173
            case 'jpg':
174
            case 'jpeg':
175
                $width = $this->getWidth();
176
                $height = $this->getHeight();
177
178
                if (($image = imagecreatetruecolor($width, $height)) === false) {
179
                    throw new ImageException('Error creating a image');
180
                }
181
182
                if (imagesavealpha($image, true) === false) {
183
                    throw new ImageException('Error saving the alpha chanel of the image');
184
                }
185
186
                if (isset($this->background[3])) {
187
                    $background = imagecolorallocatealpha($image, $this->background[0], $this->background[1], $this->background[2], $this->background[3]);
188
                } else {
189
                    $background = imagecolorallocate($image, $this->background[0], $this->background[1], $this->background[2]);
190
                }
191
192
                if (imagefill($image, 0, 0, $background) === false) {
193
                    throw new ImageException('Error filling the image');
194
                }
195
196
                imagecopy($image, $this->image, 0, 0, 0, 0, $width, $height);
197
198
                imagedestroy($this->image);
199
                $this->image = $image;
200
                $this->type = IMAGETYPE_JPEG;
201
                break;
202
203
            case 'gif':
204
                $this->type = IMAGETYPE_GIF;
205
                break;
206
207
            case 'png':
208
                $this->type = IMAGETYPE_PNG;
209
                break;
210
211
            default:
212
                throw new ImageException("The image format '{$format}' is not valid");
213
        }
214
    }
215
216
    /**
217
     * {@inheritdoc}
218
     */
219
    public function resize($width, $height)
220
    {
221
        $mode = ($this->getWidth() < $width) ? IMG_BILINEAR_FIXED : IMG_BICUBIC;
222
223
        if (($image = imagescale($this->image, $width, $height, $mode)) === false) {
224
            throw new ImageException('Error resizing the image');
225
        }
226
227
        imagedestroy($this->image);
228
        $this->image = $image;
229
    }
230
231
    /**
232
     * {@inheritdoc}
233
     */
234
    public function getCropOffsets($width, $height, $method)
235
    {
236
        if (empty(static::$fallbackCropMethods[$method])) {
237
            throw new ImageException("The crop method '$method' is not available for Gd");
238
        }
239
240
        return static::$fallbackCropMethods[$method];
241
    }
242
243
    /**
244
     * {@inheritdoc}
245
     */
246
    public function crop($width, $height, $x, $y)
247
    {
248
        $crop = [
249
            'width' => $width,
250
            'height' => $height,
251
            'x' => $x,
252
            'y' => $y,
253
        ];
254
255
        if (($image = imagecrop($this->image, $crop)) === false) {
256
            throw new ImageException('Error cropping the image');
257
        }
258
259
        imagedestroy($this->image);
260
        $this->image = $image;
261
    }
262
263
    /**
264
     * {@inheritdoc}
265
     */
266
    public function rotate($angle)
267
    {
268
        $background = imagecolorallocatealpha($this->image, 0, 0, 0, 127);
269
270
        if ($background === false || ($image = imagerotate($this->image, -$angle, $background)) === false) {
271
            throw new ImageException('Error rotating the image');
272
        }
273
274
        imagedestroy($this->image);
275
        $this->image = $image;
276
    }
277
278
    /**
279
     * {@inheritdoc}
280
     */
281
    public function blur($loops)
282
    {
283
        $width = $this->getWidth();
284
        $height = $this->getHeight();
285
        $loops *= 10;
286
287
        $this->resize($width / 5, $height / 5);
288
289
        for ($x = 0; $x < $loops; $x++) {
290
            if (($x % 4) === 0) {
291
                imagefilter($this->image, IMG_FILTER_SMOOTH, -4);
292
                imagefilter($this->image, IMG_FILTER_BRIGHTNESS, 2);
293
            }
294
295
            imagefilter($this->image, IMG_FILTER_GAUSSIAN_BLUR);
296
        }
297
298
        $this->resize($width, $height);
299
    }
300
301
    /**
302
     * {@inheritdoc}
303
     */
304
    public function watermark(LibInterface $image, $x, $y)
305
    {
306
        if (!($image instanceof self)) {
307
            $image = self::createFromString($image->getString());
308
        }
309
310
        imagecopy($this->image, $image->getImage(), $x, $y, 0, 0, $image->getWidth(), $image->getHeight());
311
    }
312
313
    /**
314
     * {@inheritdoc}
315
     */
316
    public function opacity($opacity)
317
    {
318
        if ($opacity >= 100 || $opacity < 0) {
319
            return;
320
        }
321
322
        $this->format('png');
323
324
        $opacity = $opacity / 100;
325
326
        $width = $this->getWidth();
327
        $height = $this->getHeight();
328
329
        imagealphablending($this->image, false);
330
331
        for ($x = 0; $x < $width; ++$x) {
332
            for ($y = 0; $y < $height; ++$y) {
333
                $color = imagecolorat($this->image, $x, $y);
334
                $alpha = 127 - (($color >> 24) & 0xFF);
335
336
                if ($alpha <= 0) {
337
                    continue;
338
                }
339
340
                $color = ($color & 0xFFFFFF) | ((int) round(127 - $alpha * $opacity) << 24);
341
342
                imagesetpixel($this->image, $x, $y, $color);
343
            }
344
        }
345
    }
346
347
    /**
348
     * {@inheritdoc}
349
     */
350
    public function setProgressive($progressive)
351
    {
352
        imageinterlace($this->image, $progressive);
353
    }
354
}
355