Completed
Push — master ( a06a95...a1d542 )
by dan
15s
created

ImageStyler::createImage()   C

Complexity

Conditions 9
Paths 44

Size

Total Lines 66
Code Lines 37

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 66
rs 6.4099
c 0
b 0
f 0
cc 9
eloc 37
nc 44
nop 4

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * This file is part of the IrishDan\ResponsiveImageBundle package.
4
 *
5
 * (c) Daniel Byrne <[email protected]>
6
 *
7
 * For the full copyright and license information, please view the LICENSE file that was distributed with this source
8
 * code.
9
 */
10
11
namespace IrishDan\ResponsiveImageBundle\ImageProcessing;
12
13
use Intervention\Image\ImageManager as Intervention;
14
15
/**
16
 * Class ImageStyler
17
 *
18
 * @package ResponsiveImageBundle
19
 */
20
class ImageStyler
21
{
22
    /**
23
     * @var
24
     */
25
    private $compression = 90;
26
    /**
27
     * @var
28
     */
29
    private $cropCoordinates = [];
30
    /**
31
     * @var
32
     */
33
    private $driver = 'gd';
34
    /**
35
     * @var
36
     */
37
    private $focusCoordinates = [];
38
    /**
39
     * @var
40
     */
41
    private $image;
42
    /**
43
     * @var
44
     */
45
    private $manager;
46
    /**
47
     * @var array
48
     */
49
    private $styleData = [];
50
51
    /**
52
     * ImageStyler constructor.
53
     *
54
     * @param array $responsiveImageConfig
55
     */
56
    public function __construct($responsiveImageConfig = [])
57
    {
58
        if (!empty($responsiveImageConfig['image_driver'])) {
59
            $this->driver = $responsiveImageConfig['image_driver'];
60
        }
61
        if (!empty($responsiveImageConfig['image_compression'])) {
62
            $this->compression = $responsiveImageConfig['image_compression'];
63
        }
64
    }
65
66
    /**
67
     * Separates the crop and focus coordinates from the image object and stores them.
68
     *
69
     * @param $cropFocusCoords
70
     */
71
    public function setCoordinateGroups($cropFocusCoords)
72
    {
73
        // x1, y1, x2, y2:x3, y3, x4, y4
74
        $coordsSets             = explode(':', $cropFocusCoords);
75
        $this->cropCoordinates  = explode(', ', $coordsSets[0]);
76
        $this->focusCoordinates = explode(', ', $coordsSets[1]);
77
    }
78
79
    /**
80
     * Returns the style information of a defined style.
81
     *
82
     * @param array $style
83
     */
84
    public function setStyleData($style = [])
85
    {
86
        $this->styleData['effect']    = empty($style['effect']) ? null : $style['effect'];
87
        $this->styleData['width']     = empty($style['width']) ? null : $style['width'];
88
        $this->styleData['height']    = empty($style['height']) ? null : $style['height'];
89
        $this->styleData['greyscale'] = empty($style['greyscale']) ? null : $style['greyscale'];
90
    }
91
92
    /**
93
     * @param $width
94
     * @param $height
95
     */
96
    protected function scaleImage($width, $height)
97
    {
98
        $this->image->resize(
99
            $width,
100
            $height,
101
            function ($constraint) {
102
                $constraint->aspectRatio();
103
            }
104
        );
105
    }
106
107
    /**
108
     * @param        $source
109
     * @param string $driver
110
     */
111
    protected function setImage($source, $driver = 'gd')
112
    {
113
        if (empty($this->manager)) {
114
            $this->manager = new Intervention(['driver' => $driver]);
115
        }
116
        $this->image = $this->manager->make($source);
117
    }
118
119
    /**
120
     * Performs the image manipulation using current style information
121
     * and user defined crop and focus rectangles.
122
     *
123
     * @param       $source
124
     * @param       $destination
125
     * @param array $style
126
     * @param null  $cropFocusCoords
127
     *
128
     * @return string
129
     */
130
    public function createImage($source, $destination, array $style = [], $cropFocusCoords = null)
131
    {
132
        $this->setImage($source, $this->driver);
133
134
        if (!empty($style)) {
135
            $this->setStyleData($style);
136
        }
137
138
        if (!empty($cropFocusCoords)) {
139
            $this->setCoordinateGroups($cropFocusCoords);
140
        }
141
142
        if (!empty($this->styleData)) {
143
            switch ($this->styleData['effect']) {
144
                case 'scale':
145
                    // Do the crop rectangle first
146
                    // then scale the image
147
                    $this->doCropRectangle();
148
                    $this->scaleImage($this->styleData['width'], $this->styleData['height']);
149
                    break;
150
151
                case 'crop':
152
                    // If there's no focus rectangle,
153
                    // just cut out the crop rectangle.
154
                    if (empty($this->getCoordinates('focus'))) {
155
                        $this->doCropRectangle();
156
                    }
157
                    else {
158
159
                        $focusOffsetFinder = new FocusCropDataCalculator(
160
                            $this->getCoordinates('crop'),
161
                            $this->getCoordinates('focus'),
162
                            $this->styleData['width'],
163
                            $this->styleData['height']
164
                        );
165
166
                        $focusCropData = $focusOffsetFinder->getFocusCropData();
167
                        if (!empty($focusCropData)) {
168
                            $this->cropImage(
169
                                $focusCropData['width'],
170
                                $focusCropData['height'],
171
                                $focusCropData['x'],
172
                                $focusCropData['y']
173
                            );
174
                        }
175
                    }
176
177
                    $this->image->fit(
178
                        $this->styleData['width'],
179
                        $this->styleData['height'],
180
                        function ($constraint) {
181
                            $constraint->upsize();
182
                        }
183
                    );
184
185
                    break;
186
            }
187
188
            // Do greyscale.
189
            if (!empty($this->styleData['greyscale'])) {
190
                $this->image->greyscale();
191
            }
192
        }
193
194
        return $this->saveImage($destination);
195
    }
196
197
    /**
198
     * @param $width
199
     * @param $height
200
     * @param $xOffset
201
     * @param $yOffset
202
     */
203
    protected function cropImage($width, $height, $xOffset, $yOffset)
204
    {
205
        $this->image->crop(
206
            round($width),
207
            round($height),
208
            round($xOffset),
209
            round($yOffset)
210
        );
211
    }
212
213
    /**
214
     *  Crops out defined crop area.
215
     */
216
    protected function doCropRectangle()
217
    {
218
        // Get the offset.
219
        $cropCoords = $this->getCoordinates('crop');
220
        if (!empty($cropCoords)) {
221
            $geometry = new CoordinateGeometry($cropCoords[0], $cropCoords[1], $cropCoords[2], $cropCoords[3]);
222
223
            // Get the lengths.
224
            $newWidth  = $geometry->axisLength('x');
225
            $newHeight = $geometry->axisLength('y');
226
227
            // Do the initial crop.
228
            $this->image->crop($newWidth, $newHeight, $cropCoords[0], $cropCoords[1]);
229
        }
230
    }
231
232
    /**
233
     * @param string $type
234
     *
235
     * @return bool
236
     */
237
    protected function getCoordinates($type = 'crop')
238
    {
239
        $coords = $this->{$type . 'Coordinates'};
240
        $valid  = 0;
241
        foreach ($coords as $id => $coord) {
242
            if ($coord > 0) {
243
                $valid++;
244
            }
245
            $coords[$id] = round($coord);
246
        }
247
248
        if ($valid == 0) {
249
            return false;
250
        }
251
252
        return $coords;
253
    }
254
255
    /**
256
     * @param $destination
257
     *
258
     * @return mixed
259
     */
260
    protected function saveImage($destination)
261
    {
262
        $this->image->save($destination, $this->compression);
263
264
        return $destination;
265
    }
266
}