Passed
Push — master ( 08333f...623bae )
by Derek Stephen
03:17 queued 10s
created

Image::setImageStrategy()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
eloc 1
c 0
b 0
f 0
dl 0
loc 3
ccs 2
cts 2
cp 1
rs 10
cc 1
nc 1
nop 1
crap 1
1
<?php
2
3
namespace Del;
4
5
use Del\Image\Exception\NotFoundException;
6
use Del\Image\Exception\NothingLoadedException;
7
use Del\Image\Strategy\GifStrategy;
8
use Del\Image\Strategy\ImageTypeStrategyInterface;
9
use Del\Image\Strategy\JpegStrategy;
10
use Del\Image\Strategy\PngStrategy;
11
12
class Image 
13
{
14
    /** @var resource $image */
15
    private $image;
16
17
    /** @var string $fileName */
18
    private $fileName;
19
20
    /** @var ImageTypeStrategyInterface $strategy */
21
    private $strategy;
22
23
    /** @var array $strategies */
24
    private $strategies = [
25
        IMAGETYPE_JPEG => JpegStrategy::class,
26
        IMAGETYPE_GIF => GifStrategy::class,
27
        IMAGETYPE_PNG => PngStrategy::class,
28
    ];
29
30
    /**
31
     * @param string $filename
32
     */
33 25
    public function __construct($filename = null)
34
    {
35 25
        if ($filename !== null) {
36 2
            $this->fileName = $filename;
37 2
            $this->load($filename);
38
        }
39 25
    }
40
41
    /**
42
     * @param $path
43
     * @throws NotFoundException
44
     */
45 24
    private function checkFileExists($path)
46
    {
47 24
        if (!file_exists($path)) {
48 1
            throw new NotFoundException("$path does not exist");
49
        }
50 23
    }
51
52
53
    /**
54
     * @param string $filename
55
     * @throws NotFoundException
56
     */
57 24
    public function load($filename)
58
    {
59 24
        $this->checkFileExists($filename);
60 23
        $index = getimagesize($filename)[2];
61 23
        $this->strategy = new $this->strategies[$index]();
62 23
        $this->image = $this->strategy->create($filename);
63 23
    }
64
65
    /**
66
     * @param ImageTypeStrategyInterface $imageTypeStrategy
67
     */
68 1
    public function setImageStrategy(ImageTypeStrategyInterface $imageTypeStrategy): void
69
    {
70 1
        $this->strategy = $imageTypeStrategy;
71 1
    }
72
73
74
    /**
75
     *  @param string $filename
76
     *  @param int $compression
77
     *  @param string $permissions
78
     */
79 3
    public function save($filename = null, $permissions = null, $compression = 100)
80
    {
81 3
        $filename = ($filename) ?: $this->fileName;
82 3
        $this->strategy->save($this->image, $filename, $compression);
83 3
        $this->setPermissions($filename, $permissions);
84 3
    }
85
86
    /**
87
     * @param $filename
88
     * @param $permissions
89
     */
90 3
    private function setPermissions($filename, $permissions)
91
    {
92 3
        if ($permissions !== null) {
93 1
            chmod($filename, $permissions);
94
        }
95 3
    }
96
97
98
    /**
99
     * @param bool $return either output directly
100
     * @return null|string image contents
101
     */
102 17
    public function output($return = false)
103
    {
104 17
        $contents = null;
105
106 17
        if ($return) {
107 17
            ob_start();
108
        }
109
110 17
        $this->renderImage();
111
112 17
        if ($return) {
113 17
            $contents = ob_get_flush();
114
        }
115
116 17
        return $contents;
117
    }
118
119 17
    private function renderImage()
120
    {
121 17
        $this->strategy->render($this->image);
122 17
    }
123
124
    /**
125
     * @return int
126
     */
127 11
    public function getWidth()
128
    {
129 11
        return imagesx($this->image);
130
    }
131
132
    /**
133
     * @return int
134
     */
135 11
    public function getHeight()
136
    {
137 11
        return imagesy($this->image);
138
    }
139
140
    /**
141
     * @param int $height
142
     */
143 3
    public function resizeToHeight($height)
144
    {
145 3
        $ratio = $height / $this->getHeight();
146 3
        $width = $this->getWidth() * $ratio;
147 3
        $this->resize($width, $height);
148 3
    }
149
150
    /**
151
     * @param int $width
152
     */
153 4
    public function resizeToWidth($width)
154
    {
155 4
        $ratio = $width / $this->getWidth();
156 4
        $height = $this->getHeight() * $ratio;
157 4
        $this->resize($width, $height);
158 4
    }
159
160
    /**
161
     * @param int $scale %
162
     */
163 1
    public function scale($scale)
164
    {
165 1
        $width = $this->getWidth() * $scale / 100;
166 1
        $height = $this->getHeight() * $scale / 100;
167 1
        $this->resize($width, $height);
168 1
    }
169
170
    /**
171
     * @param int $width
172
     * @param int $height
173
     */
174 4
    public function resizeAndCrop($width, $height)
175
    {
176 4
        $targetRatio = $width / $height;
177 4
        $actualRatio = $this->getWidth() / $this->getHeight();
178
179 4
        if ($targetRatio == $actualRatio) {
180
            // Scale to size
181 1
            $this->resize($width, $height);
182 3
        } elseif ($targetRatio > $actualRatio) {
183
            // Resize to width, crop extra height
184 1
            $this->resizeToWidth($width);
185 1
            $this->crop($width, $height);
186
        } else {
187
            // Resize to height, crop additional width
188 2
            $this->resizeToHeight($height);
189 2
            $this->crop($width, $height);
190
        }
191 4
    }
192
193
194
    /**
195
     *  Now with added Transparency resizing feature
196
     *  @param int $width
197
     *  @param int $height
198
     */
199 9
    public function resize($width, $height)
200
    {
201 9
        $newImage = imagecreatetruecolor($width, $height);
202
203 9
        $this->strategy->handleTransparency($newImage, $this->image);
0 ignored issues
show
Bug introduced by
It seems like $newImage can also be of type false; however, parameter $newImage of Del\Image\Strategy\Image...e::handleTransparency() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

203
        $this->strategy->handleTransparency(/** @scrutinizer ignore-type */ $newImage, $this->image);
Loading history...
204
205
        // Now resample the image
206 9
        imagecopyresampled($newImage, $this->image, 0, 0, 0, 0, $width, $height, $this->getWidth(), $this->getHeight());
0 ignored issues
show
Bug introduced by
It seems like $newImage can also be of type false; however, parameter $dst_image of imagecopyresampled() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

206
        imagecopyresampled(/** @scrutinizer ignore-type */ $newImage, $this->image, 0, 0, 0, 0, $width, $height, $this->getWidth(), $this->getHeight());
Loading history...
207
208
        // And allocate to $this
209 9
        $this->image = $newImage;
0 ignored issues
show
Documentation Bug introduced by
It seems like $newImage can also be of type false. However, the property $image is declared as type resource. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
210 9
    }
211
212
213
214
215
    /**
216
     * @param int $width
217
     * @param int $height
218
     * @param string $trim
219
     */
220 4
    public function crop($width, $height, $trim = 'center')
221
    {
222 4
        $offsetX = 0;
223 4
        $offsetY = 0;
224 4
        $currentWidth = $this->getWidth();
225 4
        $currentHeight = $this->getHeight();
226
227 4
        if ($trim != 'left') {
228 4
            $offsetX = $this->getOffsetX($currentWidth, $width, $trim);
229 4
            $offsetY = $this->getOffsetY($currentHeight, $height, $trim);
230
        }
231
232 4
        $newImage = imagecreatetruecolor($width, $height);
233 4
        imagecopyresampled($newImage, $this->image, 0, 0, $offsetX, $offsetY, $width, $height, $width, $height);
0 ignored issues
show
Bug introduced by
It seems like $newImage can also be of type false; however, parameter $dst_image of imagecopyresampled() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

233
        imagecopyresampled(/** @scrutinizer ignore-type */ $newImage, $this->image, 0, 0, $offsetX, $offsetY, $width, $height, $width, $height);
Loading history...
234 4
        $this->image = $newImage;
0 ignored issues
show
Documentation Bug introduced by
It seems like $newImage can also be of type false. However, the property $image is declared as type resource. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
235 4
    }
236
237
    /**
238
     * @param $currentWidth
239
     * @param $width
240
     * @param $trim
241
     * @return float|int
242
     */
243 4
    private function getOffsetX($currentWidth, $width, $trim)
244
    {
245 4
        $offsetX = 0;
246 4
        if ($currentWidth > $width) {
247 3
            $diff = $currentWidth - $width;
248 3
            $offsetX = ($trim == 'center') ? $diff / 2 : $diff; //full diff for trim right
249
        }
250 4
        return $offsetX;
251
    }
252
253
    /**
254
     * @param $currentHeight
255
     * @param $height
256
     * @param $trim
257
     * @return float|int
258
     */
259 4
    private function getOffsetY($currentHeight, $height, $trim)
260
    {
261 4
        $offsetY = 0;
262 4
        if ($currentHeight > $height) {
263 2
            $diff = $currentHeight - $height;
264 2
            $offsetY = ($trim == 'center') ? $diff / 2 : $diff;
265
        }
266 4
        return $offsetY;
267
    }
268
269
    /**
270
     * @return mixed
271
     * @throws NothingLoadedException
272
     */
273 4
    public function getHeader()
274
    {
275 4
        if (!$this->strategy) {
276 1
            throw new NothingLoadedException();
277
        }
278 3
        return $this->strategy->getContentType();
279
    }
280
281
    /**
282
     *  Frees up memory
283
     */
284 4
    public function destroy()
285
    {
286 4
        imagedestroy($this->image);
287
    }
288
}