Passed
Push — master ( afe694...4c5a84 )
by Petr
02:23
created

Processor::create()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2.032

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 4
c 1
b 0
f 0
nc 2
nop 2
dl 0
loc 9
ccs 4
cts 5
cp 0.8
crap 2.032
rs 10
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 35
    public function __construct(Format\Factory $factory, ?IIMTranslations $lang = null)
31
    {
32 35
        $this->setImLang($lang);
33
34 35
        if (!(function_exists('imagecreatetruecolor')
35 35
            && function_exists('imagecolorallocate')
36 35
            && function_exists('imagesetpixel')
37 35
            && function_exists('imagecopyresized')
38 35
            && function_exists('imagecopyresampled')
39 35
            && function_exists('imagesx')
40 35
            && function_exists('imagesy')
41 35
            && function_exists('imagerotate')
42 35
            && function_exists('imageflip')
43
        )) {
44
            // @codeCoverageIgnoreStart
45
            throw new ImagesException($this->getImLang()->imGdLibNotPresent());
46
        }
47
        // @codeCoverageIgnoreEnd
48
49 35
        $this->factory = $factory;
50 35
    }
51
52
    /**
53
     * @param string $type
54
     * @param string $tempPath
55
     * @throws ImagesException
56
     * @return $this
57
     */
58 13
    public function load(string $type, string $tempPath): self
59
    {
60 13
        $processor = $this->factory->getByType($type, $this->getImLang());
61 12
        $this->resource = $processor->load($tempPath);
62 12
        return $this;
63
    }
64
65
    /**
66
     * @param string $type
67
     * @param string $tempPath
68
     * @throws ImagesException
69
     * @return $this
70
     */
71 9
    public function save(string $type, string $tempPath): self
72
    {
73 9
        $processor = $this->factory->getByType($type, $this->getImLang());
74 9
        $processor->save($tempPath, $this->getResource());
75 9
        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
     * @throws ImagesException
83
     * @return $this
84
     */
85 1
    public function resize(?int $width = null, ?int $height = null): self
86
    {
87 1
        $fromWidth = $this->width();
88 1
        $fromHeight = $this->height();
89 1
        $width = (!is_null($width) && (0 < $width)) ? intval($width) : $fromWidth;
90 1
        $height = (!is_null($height) && (0 < $height)) ? intval($height) : $fromHeight;
91 1
        $resource = $this->create($width, $height);
92 1
        if (false === imagecopyresized($resource, $this->getResource(), 0, 0, 0, 0, $width, $height, $fromWidth, $fromHeight)) {
93
            // @codeCoverageIgnoreStart
94
            imagedestroy($resource);
95
            throw new ImagesException($this->getImLang()->imImageCannotResize());
96
        }
97
        // @codeCoverageIgnoreEnd
98 1
        imagedestroy($this->getResource());
99 1
        $this->resource = $resource;
100 1
        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
     * @throws ImagesException
108
     * @return $this
109
     */
110 7
    public function resample(?int $width = null, ?int $height = null): self
111
    {
112 7
        $fromWidth = $this->width();
113 7
        $fromHeight = $this->height();
114 7
        $width = (!is_null($width) && (0 < $width)) ? intval($width) : $fromWidth;
115 7
        $height = (!is_null($height) && (0 < $height)) ? intval($height) : $fromHeight;
116 7
        $resource = $this->create($width, $height);
117 7
        if (false === imagecopyresampled($resource, $this->getResource(), 0, 0, 0, 0, $width, $height, $fromWidth, $fromHeight)) {
118
            // @codeCoverageIgnoreStart
119
            imagedestroy($resource);
120
            throw new ImagesException($this->getImLang()->imImageCannotResample());
121
        }
122
        // @codeCoverageIgnoreEnd
123 7
        imagedestroy($this->getResource());
124 7
        $this->resource = $resource;
125 7
        return $this;
126
    }
127
128
    /**
129
     * Orientate image by passed info
130
     * @param int $currentOrientation
131
     * @throws ImagesException
132
     * @return $this
133
     * @link https://jdhao.github.io/2019/07/31/image_rotation_exif_info/#exif-orientation-flag
134
     * @link https://stackoverflow.com/questions/7489742/php-read-exif-data-and-adjust-orientation
135
     */
136
    public function orientate(int $currentOrientation): self
137
    {
138
        $image = $this->resource; // normal
139
        if (in_array($currentOrientation, [
140
            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
            IExifConstants::EXIF_ORIENTATION_MIRROR_ON_LEFT,
148
        ])) {
149
            $image = imagerotate($this->resource, 270, 0);
150
        }
151
        if (in_array($currentOrientation, [
152
            IExifConstants::EXIF_ORIENTATION_ON_RIGHT,
153
            IExifConstants::EXIF_ORIENTATION_MIRROR_ON_RIGHT,
154
        ])) {
155
            $image = imagerotate($this->resource, 90, 0);
156
        }
157
        if (empty($image)) {
158
            // @codeCoverageIgnoreStart
159
            throw new ImagesException($this->getImLang()->imImageCannotOrientate());
160
        }
161
        // @codeCoverageIgnoreEnd
162
        if (in_array($currentOrientation, [
163
            IExifConstants::EXIF_ORIENTATION_MIRROR_SIMPLE,
164
            IExifConstants::EXIF_ORIENTATION_MIRROR_ON_LEFT,
165
            IExifConstants::EXIF_ORIENTATION_MIRROR_ON_RIGHT,
166
            IExifConstants::EXIF_ORIENTATION_MIRROR_UPSIDE_DOWN,
167
        ])) {
168
            imageflip($image, IMG_FLIP_HORIZONTAL);
169
        }
170
        $this->resource = $image;
171
172
        return $this;
173
    }
174
175
    /**
176
     * Create empty image resource
177
     * @param int $width
178
     * @param int $height
179
     * @throws ImagesException
180
     * @return \GdImage|resource
181
     */
182 8
    protected function create(int $width, int $height)
183
    {
184 8
        $resource = imagecreatetruecolor($width, $height);
185 8
        if (false === $resource) {
186
            // @codeCoverageIgnoreStart
187
            throw new ImagesException($this->getImLang()->imImageCannotCreateEmpty());
188
        }
189
        // @codeCoverageIgnoreEnd
190 8
        return $resource;
191
    }
192
193
    /**
194
     * @throws ImagesException
195
     * @return int
196
     */
197 11
    public function width(): int
198
    {
199 11
        $size = imagesx($this->getResource());
200 11
        if (false === $size) {
201
            // @codeCoverageIgnoreStart
202
            throw new ImagesException($this->getImLang()->imImageCannotGetSize());
203
        }
204
        // @codeCoverageIgnoreEnd
205 11
        return intval($size);
206
    }
207
208
    /**
209
     * @throws ImagesException
210
     * @return int
211
     */
212 13
    public function height(): int
213
    {
214 13
        $size = imagesy($this->getResource());
215 12
        if (false === $size) {
216
            // @codeCoverageIgnoreStart
217
            throw new ImagesException($this->getImLang()->imImageCannotGetSize());
218
        }
219
        // @codeCoverageIgnoreEnd
220 12
        return intval($size);
221
    }
222
223
    /**
224
     * @throws ImagesException
225
     * @return \GdImage|resource
226
     */
227 13
    public function getResource()
228
    {
229 13
        if (empty($this->resource)) {
230 1
            throw new ImagesException($this->getImLang()->imImageLoadFirst());
231
        }
232 12
        return $this->resource;
233
    }
234
}
235