Completed
Push — master ( 414557...1a28e9 )
by Derek Stephen
03:25
created

Image::__construct()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 3
nc 2
nop 1
dl 0
loc 5
ccs 4
cts 4
cp 1
crap 2
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
namespace Del;
4
5
use Del\Image\Exception\NotFoundException;
6
use Del\Image\Exception\NothingLoadedException;
7
8
class Image 
9
{
10
    /** @var resource $image */
11
    private $image;
12
13
    /** @var int $imageType */
14
    private $imageType;
15
16
    /** @var string $fileName */
17
    private $fileName;
18
19
    private $contentType = [
20
        IMAGETYPE_JPEG => 'image/jpeg',
21
        IMAGETYPE_GIF => 'image/gif',
22
        IMAGETYPE_PNG =>'image/png',
23
    ];
24
25
    private $createCommand = [
26
        IMAGETYPE_JPEG => 'imagecreatefromjpeg',
27
        IMAGETYPE_GIF => 'imagecreatefromgif',
28
        IMAGETYPE_PNG =>'imagecreatefrompng',
29
    ];
30
31
    /**
32
     * @param string $filename
33
     */
34 21
    public function __construct($filename = null)
35
    {
36 21
        if ($filename !== null) {
37 1
            $this->fileName = $filename;
38 1
            $this->load($filename);
39 1
        }
40 21
    }
41
42
    /**
43
     * @param $path
44
     * @throws NotFoundException
45
     */
46 20
    private function checkFileExists($path)
47
    {
48 20
        if (!file_exists($path)) {
49 1
            throw new NotFoundException("$path does not exist");
50
        }
51 19
    }
52
53
54
    /**
55
     * @param string $filename
56
     * @throws NotFoundException
57
     */
58 20
    public function load($filename)
59
    {
60 20
        $this->checkFileExists($filename);
61 19
        $imageInfo = getimagesize($filename);
62 19
        $this->imageType = $imageInfo[2];
63 19
        $this->image = $this->createCommand[$this->imageType]($filename);
64 19
    }
65
66
67
    /**
68
     *  @param string $filename
69
     *  @param int $compression
70
     *  @param string $permissions
71
     */
72 3
    public function save($filename = null, $compression = 100, $permissions = null)
73
    {
74 3
        $filename = ($filename) ?: $this->fileName;
75
76 3
        switch ($this->imageType) {
77 3
            case IMAGETYPE_JPEG:
78 1
                imagejpeg($this->image, $filename, $compression);
79 1
                break;
80 2
            case IMAGETYPE_GIF:
81 1
                imagegif($this->image, $filename);
82 1
                break;
83 1
            case IMAGETYPE_PNG:
84 1
                imagepng($this->image, $filename);
85 1
                break;
86 3
        }
87
88 3
        $this->setPermissions($filename, $permissions);
89 3
    }
90
91
    /**
92
     * @param $filename
93
     * @param $permissions
94
     */
95 3
    private function setPermissions($filename, $permissions)
96
    {
97 3
        if ($permissions !== null) {
98 1
            chmod($filename, (int) $permissions);
99 1
        }
100 3
    }
101
102
103
    /**
104
     * @param bool $return either output directly
105
     * @return void|string image contents
106
     */
107 14
    public function output($return = false)
108
    {
109 14
        if ($return) {
110 14
            ob_start();
111 14
        }
112
113 14
        $this->renderImage();
114
115 14
        if ($return) {
116 14
            $contents = ob_get_flush();
117 14
            return $contents;
118
        }
119
    }
120
121 14
    private function renderImage()
122
    {
123 14
        switch ($this->imageType) {
124 14
            case IMAGETYPE_JPEG:
125 3
                imagejpeg($this->image);
126 3
                break;
127 11
            case IMAGETYPE_GIF:
128 2
                imagegif($this->image);
129 2
                break;
130 9
            case IMAGETYPE_PNG:
131 9
                imagealphablending($this->image, true);
132 9
                imagesavealpha($this->image, true);
133 9
                imagepng($this->image);
134 9
                break;
135 14
        }
136 14
    }
137
138
    /**
139
     * @return int
140
     */
141 8
    public function getWidth()
142
    {
143 8
        return imagesx($this->image);
144
    }
145
146
    /**
147
     * @return int
148
     */
149 8
    public function getHeight()
150
    {
151 8
        return imagesy($this->image);
152
    }
153
154
    /**
155
     * @param int $height
156
     */
157 2
    public function resizeToHeight($height)
158
    {
159 2
        $ratio = $height / $this->getHeight();
160 2
        $width = $this->getWidth() * $ratio;
161 2
        $this->resize($width, $height);
162 2
    }
163
164
    /**
165
     * @param int $width
166
     */
167 2
    public function resizeToWidth($width)
168
    {
169 2
        $ratio = $width / $this->getWidth();
170 2
        $height = $this->getHeight() * $ratio;
171 2
        $this->resize($width, $height);
172 2
    }
173
174
    /**
175
     * @param int $scale %
176
     */
177 1
    public function scale($scale)
178
    {
179 1
        $width = $this->getWidth() * $scale / 100;
180 1
        $height = $this->getHeight() * $scale / 100;
181 1
        $this->resize($width, $height);
182 1
    }
183
184
    /**
185
     * @param int $width
186
     * @param int $height
187
     */
188 3
    public function resizeAndCrop($width, $height)
189
    {
190 3
        $targetRatio = $width / $height;
191 3
        $actualRatio = $this->getWidth() / $this->getHeight();
192
193 3
        if ($targetRatio == $actualRatio) {
194
            // Scale to size
195 1
            $this->resize($width, $height);
196 3
        } elseif ($targetRatio > $actualRatio) {
197
            // Resize to width, crop extra height
198 1
            $this->resizeToWidth($width);
199 1
            $this->crop($width, $height);
200 1
        } else {
201
            // Resize to height, crop additional width
202 1
            $this->resizeToHeight($height);
203 1
            $this->crop($width, $height);
204
        }
205 3
    }
206
207
208
    /**
209
     *  Now with added Transparency resizing feature
210
     *  @param int $width
211
     *  @param int $height
212
     */
213 6
    public function resize($width, $height)
214
    {
215 6
        $newImage = imagecreatetruecolor($width, $height);
216
217 6
        if (($this->getImageType() == IMAGETYPE_GIF) || ($this->getImageType()  == IMAGETYPE_PNG)) {
218
219
            // Get transparency color's index number
220 6
            $transparency = imagecolortransparent($this->image);
221
222
            // Is a strange index other than -1 set?
223 6
            if ($transparency >= 0) {
224
225
                // deal with alpha channels
226
                $this->prepWithExistingIndex($newImage, $transparency);
227
228 6
            } elseif ($this->getImageType() == IMAGETYPE_PNG) {
229
230
                // deal with alpha channels
231 6
                $this->prepTransparentPng($newImage);
232 6
            }
233 6
        }
234
235
        // Now resample the image
236 6
        imagecopyresampled($newImage, $this->image, 0, 0, 0, 0, $width, $height, $this->getWidth(), $this->getHeight());
237
238
        // And allocate to $this
239 6
        $this->image = $newImage;
240 6
    }
241
242
    /**
243
     * @param $resource
244
     * @param $index
245
     */
246
    private function prepWithExistingIndex($resource, $index)
247
    {
248
        // Get the array of RGB vals for the transparency index
249
        $transparentColor = imagecolorsforindex($this->image, $index);
250
251
        // Now allocate the color
252
        $transparency = imagecolorallocate($resource, $transparentColor['red'], $transparentColor['green'], $transparentColor['blue']);
253
254
        // Fill the background with the color
255
        imagefill($resource, 0, 0, $transparency);
256
257
        // And set that color as the transparent one
258
        imagecolortransparent($resource, $transparency);
259
    }
260
261
    /**
262
     * @param $resource
263
     */
264 6
    private function prepTransparentPng($resource)
265
    {
266
        // Set blending mode as false
267 6
        imagealphablending($resource, false);
268
269
        // Tell it we want to save alpha channel info
270 6
        imagesavealpha($resource, true);
271
272
        // Set the transparent color
273 6
        $color = imagecolorallocatealpha($resource, 0, 0, 0, 127);
274
275
        // Fill the image with nothingness
276 6
        imagefill($resource, 0, 0, $color);
277 6
    }
278
279
280
    /**
281
     * @param int $width
282
     * @param int $height
283
     * @param string $trim
284
     */
285 3
    public function crop($width, $height, $trim = 'center')
286
    {
287 3
        $offsetX = 0;
288 3
        $offsetY = 0;
289 3
        $currentWidth = $this->getWidth();
290 3
        $currentHeight = $this->getHeight();
291
292 3
        if ($trim != 'left') {
293 3
            if ($currentWidth > $width) {
294 2
                $diff = $currentWidth - $width;
295 2
                $offsetX = ($trim == 'center') ? $diff / 2 : $diff; //full diff for trim right
296 2
            }
297 3
            if ($currentHeight > $height) {
298 2
                $diff = $currentHeight - $height;
299 2
                $offsetY = ($trim == 'center') ? $diff / 2 : $diff;
300 2
            }
301 3
        }
302
303 3
        $newImage = imagecreatetruecolor($width, $height);
304 3
        imagecopyresampled($newImage, $this->image, 0, 0, $offsetX, $offsetY, $width, $height, $width, $height);
305 3
        $this->image = $newImage;
306 3
    }
307
308
    /**
309
     * @return mixed
310
     */
311 6
    public function getImageType()
312
    {
313 6
        return $this->imageType;
314
    }
315
316
    /**
317
     * @return mixed
318
     * @throws NothingLoadedException
319
     */
320 4
    public function getHeader()
321
    {
322 4
        if (!$this->imageType) {
323 1
            throw new NothingLoadedException();
324
        }
325 3
        return $this->contentType[$this->imageType];
326
    }
327
328
    /**
329
     *  Frees up memory
330
     */
331 1
    public function destroy()
332
    {
333 1
        imagedestroy($this->image);
334 1
    }
335
}
336