Test Failed
Push — master ( efe757...94d555 )
by Petr
08:40
created

Processor::orientate()   B

Complexity

Conditions 6
Paths 32

Size

Total Lines 37
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 6.5625

Importance

Changes 0
Metric Value
cc 6
eloc 23
c 0
b 0
f 0
nc 32
nop 1
dl 0
loc 37
rs 8.9297
ccs 9
cts 12
cp 0.75
crap 6.5625
1
<?php
2
3
namespace kalanis\kw_images\Graphics;
4
5
6
use kalanis\kw_images\ImagesException;
7
use kalanis\kw_images\Interfaces\IIMTranslations;
8
use kalanis\kw_images\Interfaces\IExifConstants;
9
use kalanis\kw_images\Traits\TLang;
10
11
12
/**
13
 * Class Processor
14
 * @package kalanis\kw_images
15
 * Pass images in temporary local storage  - cannot work with images directly in main storage
16
 */
17
class Processor
18
{
19
    use TLang;
20
21
    protected Format\Factory $factory;
22
    /** @var resource|\GdImage|null */
23
    protected $resource = null;
24
25
    /**
26
     * @param Format\Factory $factory
27
     * @param IIMTranslations|null $lang
28
     * @throws ImagesException
29 30
     */
30
    public function __construct(Format\Factory $factory, ?IIMTranslations $lang = null)
31 30
    {
32
        $this->setImLang($lang);
33 30
34 30
        if (!(function_exists('imagecreatetruecolor')
35 30
            && function_exists('imagecolorallocate')
36 30
            && function_exists('imagesetpixel')
37 30
            && function_exists('imagecopyresized')
38 30
            && function_exists('imagecopyresampled')
39 30
            && function_exists('imagesx')
40
            && function_exists('imagesy')
41
            && function_exists('imagerotate')
42
            && function_exists('imageflip')
43
        )) {
44
            // @codeCoverageIgnoreStart
45
            throw new ImagesException($this->getImLang()->imGdLibNotPresent());
46 30
        }
47 30
        // @codeCoverageIgnoreEnd
48
49
        $this->factory = $factory;
50
    }
51
52
    /**
53
     * @param string $type
54
     * @param string $tempPath
55 13
     * @throws ImagesException
56
     * @return $this
57 13
     */
58 12
    public function load(string $type, string $tempPath): self
59 12
    {
60
        $processor = $this->factory->getByType($type, $this->getImLang());
61
        $this->resource = $processor->load($tempPath);
62
        return $this;
63
    }
64
65
    /**
66
     * @param string $type
67
     * @param string $tempPath
68 9
     * @throws ImagesException
69
     * @return $this
70 9
     */
71 9
    public function save(string $type, string $tempPath): self
72 9
    {
73
        $processor = $this->factory->getByType($type, $this->getImLang());
74
        $processor->save($tempPath, $this->getResource());
75
        return $this;
76
    }
77
78
    /**
79
     * Change image size - cut it to desired size
80
     * @param int|null $width
81
     * @param int|null $height
82 1
     * @throws ImagesException
83
     * @return $this
84 1
     */
85 1
    public function resize(?int $width = null, ?int $height = null): self
86 1
    {
87 1
        $fromWidth = $this->width();
88 1
        $fromHeight = $this->height();
89 1
        $width = (!is_null($width) && (0 < $width)) ? intval($width) : $fromWidth;
90
        $height = (!is_null($height) && (0 < $height)) ? intval($height) : $fromHeight;
91
        $resource = $this->create($width, $height);
92
        if (false === imagecopyresized($resource, $this->getResource(), 0, 0, 0, 0, $width, $height, $fromWidth, $fromHeight)) {
93
            // @codeCoverageIgnoreStart
94
            imagedestroy($resource);
95 1
            throw new ImagesException($this->getImLang()->imImageCannotResize());
96 1
        }
97 1
        // @codeCoverageIgnoreEnd
98
        imagedestroy($this->getResource());
99
        $this->resource = $resource;
100
        return $this;
101
    }
102
103
    /**
104
     * Change image size - content will change its proportions according the passed sizes
105
     * @param int|null $width
106
     * @param int|null $height
107 7
     * @throws ImagesException
108
     * @return $this
109 7
     */
110 7
    public function resample(?int $width = null, ?int $height = null): self
111 7
    {
112 7
        $fromWidth = $this->width();
113 7
        $fromHeight = $this->height();
114 7
        $width = (!is_null($width) && (0 < $width)) ? intval($width) : $fromWidth;
115
        $height = (!is_null($height) && (0 < $height)) ? intval($height) : $fromHeight;
116
        $resource = $this->create($width, $height);
117
        if (false === imagecopyresampled($resource, $this->getResource(), 0, 0, 0, 0, $width, $height, $fromWidth, $fromHeight)) {
118
            // @codeCoverageIgnoreStart
119
            imagedestroy($resource);
120 7
            throw new ImagesException($this->getImLang()->imImageCannotResample());
121 7
        }
122 7
        // @codeCoverageIgnoreEnd
123
        imagedestroy($this->getResource());
124
        $this->resource = $resource;
125
        return $this;
126
    }
127
128
    /**
129
     * Orientate image by passed info
130
     * @param int $currentOrientation
131
     * @throws ImagesException
132 8
     * @return $this
133
     * @link https://jdhao.github.io/2019/07/31/image_rotation_exif_info/#exif-orientation-flag
134 8
     * @link https://stackoverflow.com/questions/7489742/php-read-exif-data-and-adjust-orientation
135 8
     */
136
    public function orientate(int $currentOrientation): self
137
    {
138
        $image = $this->resource; // normal
139
        if (in_array($currentOrientation, [
140 8
            IExifConstants::EXIF_ORIENTATION_UPSIDE_DOWN,
141
            IExifConstants::EXIF_ORIENTATION_MIRROR_UPSIDE_DOWN,
142
        ])) {
143
            $image = imagerotate($this->resource, 180, 0);
144
        }
145
        if (in_array($currentOrientation, [
146
            IExifConstants::EXIF_ORIENTATION_ON_LEFT,
147 11
            IExifConstants::EXIF_ORIENTATION_MIRROR_ON_LEFT,
148
        ])) {
149 11
            $image = imagerotate($this->resource, 270, 0);
150 11
        }
151
        if (in_array($currentOrientation, [
152
            IExifConstants::EXIF_ORIENTATION_ON_RIGHT,
153
            IExifConstants::EXIF_ORIENTATION_MIRROR_ON_RIGHT,
154
        ])) {
155 11
            $image = imagerotate($this->resource, 90, 0);
156
        }
157
        if (in_array($currentOrientation, [
158
            IExifConstants::EXIF_ORIENTATION_MIRROR_SIMPLE,
159
            IExifConstants::EXIF_ORIENTATION_MIRROR_ON_LEFT,
160
            IExifConstants::EXIF_ORIENTATION_MIRROR_ON_RIGHT,
161
            IExifConstants::EXIF_ORIENTATION_MIRROR_UPSIDE_DOWN,
162 13
        ])) {
163
            imageflip($image, IMG_FLIP_HORIZONTAL);
164 13
        }
165 12
        if (empty($image)) {
166
            // @codeCoverageIgnoreStart
167
            throw new ImagesException($this->getImLang()->imImageCannotOrientate());
168
        }
169
        // @codeCoverageIgnoreEnd
170 12
        $this->resource = $image;
171
172
        return $this;
173
    }
174
175
    /**
176
     * Create empty image resource
177 13
     * @param int $width
178
     * @param int $height
179 13
     * @throws ImagesException
180 1
     * @return \GdImage|resource
181
     */
182 12
    protected function create(int $width, int $height)
183
    {
184
        $resource = imagecreatetruecolor($width, $height);
185
        if (false === $resource) {
186
            // @codeCoverageIgnoreStart
187
            throw new ImagesException($this->getImLang()->imImageCannotCreateEmpty());
188
        }
189
        // @codeCoverageIgnoreEnd
190
        return $resource;
191
    }
192
193
    /**
194
     * @throws ImagesException
195
     * @return int
196
     */
197
    public function width(): int
198
    {
199
        $size = imagesx($this->getResource());
200
        if (false === $size) {
201
            // @codeCoverageIgnoreStart
202
            throw new ImagesException($this->getImLang()->imImageCannotGetSize());
203
        }
204
        // @codeCoverageIgnoreEnd
205
        return intval($size);
206
    }
207
208
    /**
209
     * @throws ImagesException
210
     * @return int
211
     */
212
    public function height(): int
213
    {
214
        $size = imagesy($this->getResource());
215
        if (false === $size) {
216
            // @codeCoverageIgnoreStart
217
            throw new ImagesException($this->getImLang()->imImageCannotGetSize());
218
        }
219
        // @codeCoverageIgnoreEnd
220
        return intval($size);
221
    }
222
223
    /**
224
     * @throws ImagesException
225
     * @return \GdImage|resource
226
     */
227
    public function getResource()
228
    {
229
        if (empty($this->resource)) {
230
            throw new ImagesException($this->getImLang()->imImageLoadFirst());
231
        }
232
        return $this->resource;
233
    }
234
}
235