|
1
|
|
|
<?php |
|
2
|
|
|
|
|
3
|
|
|
namespace Compolomus\Compomage; |
|
4
|
|
|
|
|
5
|
|
|
use Compolomus\Compomage\Interfaces\ImageInterface; |
|
6
|
|
|
use Exception; |
|
7
|
|
|
use InvalidArgumentException; |
|
8
|
|
|
use LogicException; |
|
9
|
|
|
use RuntimeException; |
|
10
|
|
|
use SplFileObject; |
|
11
|
|
|
|
|
12
|
|
|
abstract class AbstractImage |
|
13
|
|
|
{ |
|
14
|
|
|
protected const POSITIONS = [ |
|
15
|
|
|
'NORTHWEST' => ['x' => 0, 'y' => 0, 'padX' => 10, 'padY' => 10], |
|
16
|
|
|
'NORTH' => ['x' => 1, 'y' => 0, 'padX' => 0, 'padY' => 10], |
|
17
|
|
|
'NORTHEAST' => ['x' => 2, 'y' => 0, 'padX' => -10, 'padY' => 10], |
|
18
|
|
|
'WEST' => ['x' => 0, 'y' => 1, 'padX' => 10, 'padY' => 0], |
|
19
|
|
|
'CENTER' => ['x' => 1, 'y' => 1, 'padX' => 0, 'padY' => 0], |
|
20
|
|
|
'EAST' => ['x' => 2, 'y' => 1, 'padX' => -10, 'padY' => 0], |
|
21
|
|
|
'SOUTHWEST' => ['x' => 0, 'y' => 2, 'padX' => 10, 'padY' => -10], |
|
22
|
|
|
'SOUTH' => ['x' => 1, 'y' => 2, 'padX' => 0, 'padY' => -10], |
|
23
|
|
|
'SOUTHEAST' => ['x' => 2, 'y' => 2, 'padX' => -10, 'padY' => -10] |
|
24
|
|
|
]; |
|
25
|
|
|
|
|
26
|
|
|
protected $width; |
|
27
|
|
|
|
|
28
|
|
|
protected $height; |
|
29
|
|
|
|
|
30
|
|
|
/** |
|
31
|
|
|
* @return \Imagick|resource |
|
32
|
|
|
*/ |
|
33
|
|
|
abstract public function getImage(); |
|
34
|
|
|
|
|
35
|
|
|
/** |
|
36
|
|
|
* @param string $mode |
|
37
|
|
|
* @param int $param |
|
38
|
|
|
* @return ImageInterface |
|
39
|
|
|
* @throws InvalidArgumentException |
|
40
|
|
|
*/ |
|
41
|
2 |
|
public function resizeBy(string $mode, int $param): ImageInterface |
|
42
|
|
|
{ |
|
43
|
2 |
|
switch ($mode) { |
|
44
|
2 |
|
case 'width': |
|
45
|
1 |
|
return $this->resizeByWidth($param); |
|
46
|
2 |
|
case 'height': |
|
47
|
1 |
|
return $this->resizeByHeight($param); |
|
48
|
2 |
|
case 'percent': |
|
49
|
1 |
|
return $this->resizeByPercent($param); |
|
50
|
|
|
default: |
|
51
|
1 |
|
throw new InvalidArgumentException('Unsupported mode type by resize'); |
|
52
|
|
|
} |
|
53
|
|
|
} |
|
54
|
|
|
|
|
55
|
|
|
/** |
|
56
|
|
|
* @param int $width |
|
57
|
|
|
* @return ImageInterface |
|
58
|
|
|
*/ |
|
59
|
1 |
|
public function resizeByWidth(int $width): ImageInterface |
|
60
|
|
|
{ |
|
61
|
1 |
|
return $this->resize($width, $this->getHeight() * ($width / $this->getWidth())); |
|
62
|
|
|
} |
|
63
|
|
|
|
|
64
|
|
|
/** |
|
65
|
|
|
* @param int $width |
|
66
|
|
|
* @param int $height |
|
67
|
|
|
* @return ImageInterface |
|
68
|
|
|
*/ |
|
69
|
|
|
abstract protected function resize(int $width, int $height): ImageInterface; |
|
70
|
|
|
|
|
71
|
|
|
/** |
|
72
|
|
|
* @return int |
|
73
|
|
|
*/ |
|
74
|
4 |
|
public function getHeight(): int |
|
75
|
|
|
{ |
|
76
|
4 |
|
return $this->height; |
|
77
|
|
|
} |
|
78
|
|
|
|
|
79
|
|
|
/** |
|
80
|
|
|
* @param int $height |
|
81
|
|
|
*/ |
|
82
|
13 |
|
protected function setHeight(int $height): void |
|
83
|
|
|
{ |
|
84
|
13 |
|
$this->height = $height; |
|
85
|
13 |
|
} |
|
86
|
|
|
|
|
87
|
|
|
/** |
|
88
|
|
|
* @return int |
|
89
|
|
|
*/ |
|
90
|
5 |
|
public function getWidth(): int |
|
91
|
|
|
{ |
|
92
|
5 |
|
return $this->width; |
|
93
|
|
|
} |
|
94
|
|
|
|
|
95
|
|
|
/** |
|
96
|
|
|
* @param int $width |
|
97
|
|
|
*/ |
|
98
|
13 |
|
protected function setWidth(int $width): void |
|
99
|
|
|
{ |
|
100
|
13 |
|
$this->width = $width; |
|
101
|
13 |
|
} |
|
102
|
|
|
|
|
103
|
|
|
/** |
|
104
|
|
|
* @param int $height |
|
105
|
|
|
* @return ImageInterface |
|
106
|
|
|
*/ |
|
107
|
1 |
|
public function resizeByHeight(int $height): ImageInterface |
|
108
|
|
|
{ |
|
109
|
1 |
|
return $this->resize($this->getWidth() * ($height / $this->getHeight()), $height); |
|
110
|
|
|
} |
|
111
|
|
|
|
|
112
|
|
|
/** |
|
113
|
|
|
* @param int $percent |
|
114
|
|
|
* @return ImageInterface |
|
115
|
|
|
*/ |
|
116
|
1 |
|
public function resizeByPercent(int $percent): ImageInterface |
|
117
|
|
|
{ |
|
118
|
1 |
|
$width = $this->getWidth() * ($percent / 100); |
|
119
|
1 |
|
$height = $this->getHeight() * ($percent / 100); |
|
120
|
1 |
|
return $this->resize($width, $height); |
|
121
|
|
|
} |
|
122
|
|
|
|
|
123
|
|
|
/** |
|
124
|
|
|
* @param Image $watermark |
|
125
|
|
|
* @param string $position |
|
126
|
|
|
* @return ImageInterface |
|
127
|
|
|
* @throws InvalidArgumentException |
|
128
|
|
|
*/ |
|
129
|
1 |
|
public function watermark(Image $watermark, string $position): ImageInterface |
|
130
|
|
|
{ |
|
131
|
1 |
|
if (!array_key_exists(strtoupper($position), self::POSITIONS)) { |
|
132
|
1 |
|
throw new InvalidArgumentException('Wrong position'); |
|
133
|
|
|
} |
|
134
|
|
|
|
|
135
|
|
|
return $this->prepareWatermark( |
|
136
|
|
|
$watermark, |
|
137
|
|
|
(int)((($this->getWidth() - $watermark->getWidth()) / 2) * self::POSITIONS[strtoupper($position)]['x']) + self::POSITIONS[strtoupper($position)]['padX'], |
|
138
|
|
|
(int)((($this->getHeight() - $watermark->getHeight()) / 2) * self::POSITIONS[strtoupper($position)]['y']) + self::POSITIONS[strtoupper($position)]['padY'] |
|
139
|
|
|
); |
|
140
|
|
|
} |
|
141
|
|
|
|
|
142
|
|
|
/** |
|
143
|
|
|
* @param Image $watermark |
|
144
|
|
|
* @param int $x |
|
145
|
|
|
* @param int $y |
|
146
|
|
|
* @return ImageInterface |
|
147
|
|
|
*/ |
|
148
|
|
|
abstract protected function prepareWatermark(Image $watermark, int $x, int $y): ImageInterface; |
|
149
|
|
|
|
|
150
|
|
|
/** |
|
151
|
|
|
* @param int $width |
|
152
|
|
|
* @param int $height |
|
153
|
|
|
* @return ImageInterface |
|
154
|
|
|
*/ |
|
155
|
2 |
|
public function thumbnail(int $width, int $height): ImageInterface |
|
156
|
|
|
{ |
|
157
|
2 |
|
$newHeight = $height; |
|
158
|
2 |
|
$newWidth = $width; |
|
159
|
|
|
|
|
160
|
2 |
|
$this->getWidth() / $this->getHeight() >= $width / $height |
|
161
|
1 |
|
? $newWidth = (int)($this->getWidth() / ($this->getHeight() / $height)) |
|
162
|
1 |
|
: $newHeight = (int)($this->getHeight() / ($this->getWidth() / $width)); |
|
163
|
|
|
|
|
164
|
2 |
|
return $this->prepareThumbnail($width, $height, $newWidth, $newHeight); |
|
|
|
|
|
|
165
|
|
|
} |
|
166
|
|
|
|
|
167
|
|
|
/** |
|
168
|
|
|
* @param int $width |
|
169
|
|
|
* @param int $height |
|
170
|
|
|
* @return ImageInterface |
|
171
|
|
|
*/ |
|
172
|
|
|
abstract protected function prepareThumbnail(int $width, int $height): ImageInterface; |
|
173
|
|
|
|
|
174
|
|
|
/** |
|
175
|
|
|
* @return string chunked base64 |
|
176
|
|
|
*/ |
|
177
|
1 |
|
public function getBase64(): string |
|
178
|
|
|
{ |
|
179
|
1 |
|
return base64_encode((string)$this); |
|
180
|
|
|
|
|
181
|
|
|
} |
|
182
|
|
|
|
|
183
|
|
|
/** |
|
184
|
|
|
* @return string |
|
185
|
|
|
*/ |
|
186
|
|
|
abstract public function __toString(): string; |
|
187
|
|
|
|
|
188
|
|
|
/** |
|
189
|
|
|
* @param $image |
|
190
|
|
|
*/ |
|
191
|
|
|
abstract protected function setImage($image): void; |
|
192
|
|
|
|
|
193
|
|
|
/** |
|
194
|
|
|
* System method |
|
195
|
|
|
* |
|
196
|
|
|
* @param void |
|
197
|
|
|
*/ |
|
198
|
|
|
abstract protected function setSizes(): void; |
|
199
|
|
|
|
|
200
|
|
|
/** |
|
201
|
|
|
* @param string $image |
|
202
|
|
|
* @throws Exception |
|
203
|
|
|
*/ |
|
204
|
14 |
|
protected function init(string $image): void |
|
205
|
|
|
{ |
|
206
|
|
|
switch ($image) { |
|
207
|
|
|
// base64 |
|
208
|
14 |
|
case base64_encode(base64_decode($image, true)) === $image: |
|
209
|
4 |
|
$this->getImageByBase64($image); |
|
210
|
3 |
|
break; |
|
211
|
|
|
// URL |
|
212
|
12 |
|
case (0 === strpos($image, 'http')): |
|
213
|
3 |
|
$this->getImageByURL($image); |
|
214
|
2 |
|
break; |
|
215
|
|
|
// Local file |
|
216
|
|
|
default: |
|
217
|
11 |
|
$this->tmp(file_get_contents($image)); |
|
218
|
|
|
} |
|
219
|
12 |
|
} |
|
220
|
|
|
|
|
221
|
|
|
/** |
|
222
|
|
|
* @param string $base64 |
|
223
|
|
|
* @return void |
|
224
|
|
|
* @throws Exception |
|
225
|
|
|
*/ |
|
226
|
4 |
|
protected function getImageByBase64(string $base64): void |
|
227
|
|
|
{ |
|
228
|
4 |
|
$this->tmp(base64_decode($base64)); |
|
229
|
3 |
|
} |
|
230
|
|
|
|
|
231
|
|
|
/** |
|
232
|
|
|
* @param string $source |
|
233
|
|
|
* @return ImageInterface |
|
234
|
|
|
*/ |
|
235
|
|
|
abstract protected function tmp(string $source): ImageInterface; |
|
236
|
|
|
|
|
237
|
|
|
/** |
|
238
|
|
|
* @param string $url |
|
239
|
|
|
* @return InvalidArgumentException|null |
|
240
|
|
|
* @throws Exception |
|
241
|
|
|
* @throws InvalidArgumentException |
|
242
|
|
|
* @throws LogicException |
|
243
|
|
|
* @throws RuntimeException |
|
244
|
|
|
*/ |
|
245
|
3 |
|
protected function getImageByURL(string $url): ?InvalidArgumentException |
|
246
|
|
|
{ |
|
247
|
3 |
|
if (@!getimagesize($url)) { |
|
248
|
1 |
|
throw new InvalidArgumentException('Unsupported image type'); |
|
249
|
|
|
} |
|
250
|
2 |
|
$upload = new SplFileObject($url, 'rb'); |
|
251
|
2 |
|
$image = ''; |
|
252
|
2 |
|
while (!$upload->eof()) { |
|
253
|
2 |
|
$image .= $upload->fgets(); |
|
254
|
|
|
} |
|
255
|
2 |
|
$this->tmp($image); |
|
256
|
|
|
|
|
257
|
2 |
|
return null; |
|
258
|
|
|
} |
|
259
|
|
|
} |
|
260
|
|
|
|
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.
If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.
In this case you can add the
@ignorePhpDoc annotation to the duplicate definition and it will be ignored.