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

ImageMaker.php (2 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
namespace IrishDan\ResponsiveImageBundle;
4
5
use Intervention\Image\ImageManager;
6
7
/**
8
 * Class ImageMaker
9
 *
10
 * @package ResponsiveImageBundle
11
 */
12
class ImageMaker
13
{
14
    use CoordinateLengthCalculator;
15
16
    /**
17
     * @var
18
     */
19
    private $compression;
20
    /**
21
     * @var
22
     */
23
    private $cropCoordinates = [];
24
    /**
25
     * @var
26
     */
27
    private $driver;
28
    /**
29
     * @var FileManager
30
     */
31
    private $fileManager;
32
    /**
33
     * @var
34
     */
35
    private $focusCoordinates = [];
36
    /**
37
     * @var
38
     */
39
    private $img;
40
    /**
41
     * @var
42
     */
43
    private $manager;
44
    /**
45
     * @var array
46
     */
47
    private $styleData = [];
48
49
    /**
50
     * Imager constructor.
51
     *
52
     * @param FileManager $system
53
     * @param array       $responsiveImageConfig
54
     * @internal param $driver
55
     * @internal param $compression
56
     */
57
    public function __construct(FileManager $system, $responsiveImageConfig = [])
58
    {
59
        $this->fileManager = $system;
60
        if (!empty($responsiveImageConfig['debug'])) {
61
            $this->debug = $responsiveImageConfig['debug'];
0 ignored issues
show
The property debug does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
62
        }
63
        if (!empty($responsiveImageConfig['image_driver'])) {
64
            $this->driver = $responsiveImageConfig['image_driver'];
65
        }
66
        if (!empty($responsiveImageConfig['image_compression'])) {
67
            $this->compression = $responsiveImageConfig['image_compression'];
68
        }
69
    }
70
71
    /**
72
     * Separates the crop and focus coordinates from the image object and stores them.
73
     *
74
     * @param $cropFocusCoords
75
     */
76
    public function setCoordinateGroups($cropFocusCoords)
77
    {
78
        // x1, y1, x2, y2:x3, y3, x4, y4
79
        $coordsSets = explode(':', $cropFocusCoords);
80
        $this->cropCoordinates = explode(', ', $coordsSets[0]);
81
        $this->focusCoordinates = explode(', ', $coordsSets[1]);
82
    }
83
84
    /**
85
     * Returns the style information of a defined style.
86
     *
87
     * @param array $style
88
     */
89
    public function setStyleData($style = [])
90
    {
91
        $this->styleData['effect'] = empty($style['effect']) ? null : $style['effect'];
92
        $this->styleData['width'] = empty($style['width']) ? null : $style['width'];
93
        $this->styleData['height'] = empty($style['height']) ? null : $style['height'];
94
        $this->styleData['greyscale'] = empty($style['greyscale']) ? null : $style['greyscale'];
95
    }
96
97
    protected function scaleImage($width, $height)
98
    {
99
        $this->img->resize($width, $height, function ($constraint) {
100
            $constraint->aspectRatio();
101
        });
102
    }
103
104
    protected function setImage($source, $driver = 'gd')
105
    {
106
        if (empty($this->manager)) {
107
            $this->manager = new ImageManager(['driver' => $driver]);
108
        }
109
        $this->img = $this->manager->make($source);
110
    }
111
112
    /**
113
     * Performs the image manipulation using current style information
114
     * and user defined crop and focus rectangles.
115
     *
116
     * @param       $source
117
     * @param       $destination
118
     * @param array $style
119
     * @param null  $cropFocusCoords
120
     * @return string
121
     */
122
    public function createImage($source, $destination, array $style = [], $cropFocusCoords = null)
123
    {
124
        $this->setImage($source, $this->driver);
125
126
        if (!empty($style)) {
127
            $this->setStyleData($style);
128
        }
129
130
        if (!empty($cropFocusCoords)) {
131
            $this->setCoordinateGroups($cropFocusCoords);
132
        }
133
134
        if (!empty($this->styleData)) {
135
            switch ($this->styleData['effect']) {
136
                case 'scale':
137
                    // Do the crop rectangle first
138
                    // then scale the image
139
                    $this->doCropRectangle();
140
                    $this->scaleImage($this->styleData['width'], $this->styleData['height']);
141
                    break;
142
143
                case 'crop':
144
                    // If there's no focus rectangle,
145
                    // just cut out the crop rectangle.
146
                    if (empty($this->getCoordinates('focus'))) {
147
                        $this->doCropRectangle();
148
                    } else {
149
150
                        $focusOffsetFinder = new FocusCropDataCalculator(
151
                            $this->getCoordinates('crop'),
152
                            $this->getCoordinates('focus'),
153
                            $this->styleData['width'],
154
                            $this->styleData['height']
155
                        );
156
157
                        $focusCropData = $focusOffsetFinder->getFocusCropData();
158
                        if (!empty($focusCropData)) {
159
                            $this->cropImage($focusCropData['width'], $focusCropData['height'], $focusCropData['x'], $focusCropData['y']);
160
                        }
161
                    }
162
163
                    $this->img->fit($this->styleData['width'], $this->styleData['height'], function ($constraint) {
164
                        $constraint->upsize();
165
                    });
166
167
                    break;
168
            }
169
170
            // Do greyscale.
171
            if (!empty($this->styleData['greyscale'])) {
172
                $this->img->greyscale();
173
            }
174
        }
175
176
        return $this->saveImage($destination, $source);
177
    }
178
179
    protected function cropImage($width, $height, $xOffset, $yOffset)
180
    {
181
        $this->img->crop(
182
            round($width),
183
            round($height),
184
            round($xOffset),
185
            round($yOffset)
186
        );
187
    }
188
189
    /**
190
     *  Crops out defined crop area.
191
     */
192
    protected function doCropRectangle()
193
    {
194
        // Get the offset.
195
        $cropCoords = $this->getCoordinates('crop');
196
        if (!empty($cropCoords)) {
197
            $x1 = $cropCoords[0];
198
            $y1 = $cropCoords[1];
199
200
            // Get the lengths.
201
            // @TODO: Methods not existing
202
            $newWidth = $this->getLength('x', $cropCoords);
203
            $newHeight = $this->getLength('y', $cropCoords);
204
205
            // Do the initial crop.
206
            $this->img->crop($newWidth, $newHeight, $x1, $y1);
207
        }
208
    }
209
210
    /**
211
     * Returns either the crop or focus rectangle coordinates.
212
     *
213
     * @param string $type
214
     * @return mixed
215
     */
216
    protected function getCoordinates($type = 'crop')
217
    {
218
        $coords = $this->{$type . 'Coordinates'};
219
        $valid = 0;
220
        foreach ($coords as $id => $coord) {
221
            if ($coord > 0) {
222
                $valid++;
223
            }
224
            $coords[$id] = round($coord);
225
        }
226
227
        if ($valid == 0) {
228
            return false;
229
        }
230
231
        return $coords;
232
    }
233
234
    /**
235
     * Saves the new image.
236
     *
237
     * @param $destination
238
     * @param $source
239
     * @return string
240
     */
241
    protected function saveImage($destination, $source)
242
    {
243
        // Check if directory exists and if not create it.
244
        $this->fileManager->directoryExists($destination, true);
245
246
        // Get the file name from source path.
247
        $filename = $this->fileManager->getFilenameFromPath($source);
248
        $fullPath = $destination . '/' . $filename;
249
250
        $this->img->save($fullPath, $this->compression);
251
252
        return $fullPath;
253
    }
254
255
    /**
256
     * Gets vertical or horizontal length between two coordinates (x, y, x2, y2).
257
     *
258
     * @param string $type
259
     * @param array  $coords
260
     * @return mixed
261
     */
262 View Code Duplication
    protected function getLength($type = 'x', array $coords)
0 ignored issues
show
This method seems to be duplicated in 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...
263
    {
264
        $type = strtolower($type);
265
        if ($type == 'x') {
266
            return $coords[2] - $coords[0];
267
        } else {
268
            return $coords[3] - $coords[1];
269
        }
270
    }
271
}