1 | <?php |
||||||||||
2 | |||||||||||
3 | namespace floor12\imagenator; |
||||||||||
4 | |||||||||||
5 | use floor12\imagenator\exception\FontNotFoundException; |
||||||||||
6 | use floor12\imagenator\exception\ImageNotFoundException; |
||||||||||
7 | use floor12\imagenator\exception\InvalidFontSizeException; |
||||||||||
8 | use floor12\imagenator\exception\InvalidHexColorException; |
||||||||||
9 | use floor12\imagenator\exception\InvalidPositionValueException; |
||||||||||
10 | use floor12\imagenator\exception\InvalidRowHeightException; |
||||||||||
11 | |||||||||||
12 | class Imagenator |
||||||||||
13 | { |
||||||||||
14 | const DEFAULT_IMAGE = __DIR__ . '/../assets/default.png'; |
||||||||||
15 | /** |
||||||||||
16 | * @var string Path to TTF font file |
||||||||||
17 | */ |
||||||||||
18 | protected $font = __DIR__ . '/../assets/Rubik.ttf'; |
||||||||||
19 | /** |
||||||||||
20 | * @var string |
||||||||||
21 | */ |
||||||||||
22 | protected $text = "Dont forget to put some text here :-)"; |
||||||||||
23 | /** |
||||||||||
24 | * @var false|resource |
||||||||||
25 | */ |
||||||||||
26 | protected $image; |
||||||||||
27 | /** |
||||||||||
28 | * @var int |
||||||||||
29 | */ |
||||||||||
30 | protected $imageWidth; |
||||||||||
31 | /** |
||||||||||
32 | * @var int |
||||||||||
33 | */ |
||||||||||
34 | protected $imageHeight; |
||||||||||
35 | /** |
||||||||||
36 | * @var int |
||||||||||
37 | */ |
||||||||||
38 | protected $rowHeight = 8; |
||||||||||
39 | /** |
||||||||||
40 | * @var int |
||||||||||
41 | */ |
||||||||||
42 | protected $marginTopInPercents = 50; |
||||||||||
43 | /** |
||||||||||
44 | * @var int |
||||||||||
45 | */ |
||||||||||
46 | protected $paddingLeftRightInPercents = 5; |
||||||||||
47 | /** |
||||||||||
48 | * @var int Default color is white |
||||||||||
49 | */ |
||||||||||
50 | private $textColor = '16777215'; |
||||||||||
51 | /** |
||||||||||
52 | * @var int |
||||||||||
53 | */ |
||||||||||
54 | private $fontSizeInPercents = 5; |
||||||||||
55 | /** |
||||||||||
56 | * @var array |
||||||||||
57 | */ |
||||||||||
58 | private $rows = []; |
||||||||||
59 | /** |
||||||||||
60 | * @var float|int |
||||||||||
61 | */ |
||||||||||
62 | private $positionX; |
||||||||||
63 | /** |
||||||||||
64 | * @var float|int |
||||||||||
65 | */ |
||||||||||
66 | private $positionStartY; |
||||||||||
67 | /** |
||||||||||
68 | * @var float|int |
||||||||||
69 | */ |
||||||||||
70 | private $rowHeightInPx; |
||||||||||
71 | /** |
||||||||||
72 | * @var float|int |
||||||||||
73 | */ |
||||||||||
74 | private $fontSizeInPx; |
||||||||||
75 | |||||||||||
76 | /** |
||||||||||
77 | * Imagenator constructor. |
||||||||||
78 | * @param string $backgroundImagePath |
||||||||||
79 | * @throws ImageNotFoundException |
||||||||||
80 | */ |
||||||||||
81 | public function __construct(string $backgroundImagePath = self::DEFAULT_IMAGE) |
||||||||||
82 | { |
||||||||||
83 | $this->loadImage($backgroundImagePath); |
||||||||||
84 | } |
||||||||||
85 | |||||||||||
86 | /** |
||||||||||
87 | * @param string $backgroundImagePath |
||||||||||
88 | * @throws ImageNotFoundException |
||||||||||
89 | */ |
||||||||||
90 | protected function loadImage(string $backgroundImagePath) |
||||||||||
91 | { |
||||||||||
92 | if (!file_exists($backgroundImagePath)) |
||||||||||
93 | throw new ImageNotFoundException(); |
||||||||||
94 | $this->image = imagecreatefrompng($backgroundImagePath); |
||||||||||
95 | list($this->imageWidth, $this->imageHeight) = getimagesize($backgroundImagePath); |
||||||||||
96 | } |
||||||||||
97 | |||||||||||
98 | /** |
||||||||||
99 | * @param string $resultImagePath |
||||||||||
100 | * @return bool |
||||||||||
101 | * @throws FontNotFoundException |
||||||||||
102 | */ |
||||||||||
103 | public function generate(string $resultImagePath): bool |
||||||||||
104 | { |
||||||||||
105 | $this->calculateParams(); |
||||||||||
106 | $this->prepareRows(); |
||||||||||
107 | $this->putRowsToImage(); |
||||||||||
108 | return $this->saveImage($resultImagePath); |
||||||||||
109 | } |
||||||||||
110 | |||||||||||
111 | /** |
||||||||||
112 | * @param string $pathToSave |
||||||||||
113 | * @return bool |
||||||||||
114 | */ |
||||||||||
115 | protected function saveImage(string $pathToSave): bool |
||||||||||
116 | { |
||||||||||
117 | return imagepng($this->image, $pathToSave) && imagedestroy($this->image); |
||||||||||
0 ignored issues
–
show
Bug
introduced
by
Loading history...
It seems like
$this->image can also be of type boolean ; however, parameter $image of imagedestroy() 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
Loading history...
|
|||||||||||
118 | } |
||||||||||
119 | |||||||||||
120 | protected function calculateParams() |
||||||||||
121 | { |
||||||||||
122 | $this->positionStartY = (int)($this->imageHeight / 100 * $this->marginTopInPercents); |
||||||||||
123 | $this->rowHeightInPx = (int)($this->imageHeight / 100 * $this->rowHeight); |
||||||||||
124 | $this->fontSizeInPx = (int)($this->imageHeight / 100 * $this->fontSizeInPercents); |
||||||||||
125 | $this->positionX = (int)($this->imageWidth / 100 * $this->paddingLeftRightInPercents); |
||||||||||
126 | } |
||||||||||
127 | |||||||||||
128 | /** |
||||||||||
129 | * @throws FontNotFoundException |
||||||||||
130 | */ |
||||||||||
131 | protected function prepareRows(): void |
||||||||||
132 | { |
||||||||||
133 | if (!file_exists($this->font)) |
||||||||||
134 | throw new FontNotFoundException(); |
||||||||||
135 | |||||||||||
136 | $wordsArray = explode(' ', $this->text); |
||||||||||
137 | $validRowWidth = $this->imageWidth - $this->positionX * 2; |
||||||||||
138 | $currentRow = 0; |
||||||||||
139 | |||||||||||
140 | foreach ($wordsArray as $word) { |
||||||||||
141 | $testRow = isset($this->rows[$currentRow]) ? array_merge($this->rows[$currentRow], [$word]) : [$word]; |
||||||||||
142 | $imageBox = imagettfbbox($this->fontSizeInPx, 0, $this->font, implode('', $testRow)); |
||||||||||
143 | if ($imageBox[2] >= $validRowWidth) { |
||||||||||
144 | $lastWord = end($this->rows[$currentRow]); |
||||||||||
145 | if (mb_strlen($lastWord) <= 2) { |
||||||||||
146 | $this->rows[$currentRow + 1][] = array_pop($this->rows[$currentRow]); |
||||||||||
147 | } |
||||||||||
148 | $this->rows[++$currentRow][] = $word; |
||||||||||
149 | } else { |
||||||||||
150 | $this->rows[$currentRow][] = $word; |
||||||||||
151 | } |
||||||||||
152 | } |
||||||||||
153 | } |
||||||||||
154 | |||||||||||
155 | /** |
||||||||||
156 | * |
||||||||||
157 | */ |
||||||||||
158 | protected function putRowsToImage() |
||||||||||
159 | { |
||||||||||
160 | foreach ($this->rows as $rowNumber => $row) { |
||||||||||
161 | $string = implode(' ', $row); |
||||||||||
162 | $positionY = (int)$this->positionStartY + ($rowNumber * $this->rowHeightInPx); |
||||||||||
163 | imagettftext($this->image, $this->fontSizeInPx, 0, $this->positionX, $positionY, $this->textColor, $this->font, $string); |
||||||||||
0 ignored issues
–
show
$positionY of type double is incompatible with the type integer expected by parameter $y of imagettftext() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
It seems like
$this->image can also be of type boolean ; however, parameter $image of imagettftext() 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
Loading history...
It seems like
$this->positionX can also be of type double ; however, parameter $x of imagettftext() does only seem to accept integer , 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
Loading history...
|
|||||||||||
164 | } |
||||||||||
165 | } |
||||||||||
166 | |||||||||||
167 | /** |
||||||||||
168 | * @param string $text |
||||||||||
169 | * @return self |
||||||||||
170 | */ |
||||||||||
171 | public |
||||||||||
172 | function setText(string $text): self |
||||||||||
173 | { |
||||||||||
174 | $this->text = $text; |
||||||||||
175 | return $this; |
||||||||||
176 | } |
||||||||||
177 | |||||||||||
178 | /** |
||||||||||
179 | * @param string $font |
||||||||||
180 | * @return self |
||||||||||
181 | */ |
||||||||||
182 | public |
||||||||||
183 | function setFont(string $font): self |
||||||||||
184 | { |
||||||||||
185 | $this->font = $font; |
||||||||||
186 | return $this; |
||||||||||
187 | } |
||||||||||
188 | |||||||||||
189 | /** |
||||||||||
190 | * @param string $colorInHex |
||||||||||
191 | * @return self |
||||||||||
192 | * @throws InvalidHexColorException |
||||||||||
193 | */ |
||||||||||
194 | public |
||||||||||
195 | function setColor(string $colorInHex): self |
||||||||||
196 | { |
||||||||||
197 | $colorInHex = str_replace('#', '', $colorInHex); |
||||||||||
198 | |||||||||||
199 | if (!ctype_xdigit($colorInHex) || strlen($colorInHex) !== 6) |
||||||||||
200 | throw new InvalidHexColorException(); |
||||||||||
201 | |||||||||||
202 | $red = hexdec(substr($colorInHex, 0, 2)); |
||||||||||
203 | $green = hexdec(substr($colorInHex, 2, 2)); |
||||||||||
204 | $blue = hexdec(substr($colorInHex, 4, 2)); |
||||||||||
205 | $this->textColor = imagecolorallocate($this->image, $red, $green, $blue); |
||||||||||
0 ignored issues
–
show
It seems like
$green can also be of type double ; however, parameter $green of imagecolorallocate() does only seem to accept integer , 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
Loading history...
It seems like
$red can also be of type double ; however, parameter $red of imagecolorallocate() does only seem to accept integer , 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
Loading history...
It seems like
$blue can also be of type double ; however, parameter $blue of imagecolorallocate() does only seem to accept integer , 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
Loading history...
It seems like
$this->image can also be of type boolean ; however, parameter $image of imagecolorallocate() 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
Loading history...
|
|||||||||||
206 | return $this; |
||||||||||
207 | } |
||||||||||
208 | |||||||||||
209 | /** |
||||||||||
210 | * @param int $size |
||||||||||
211 | * @return Imagenator |
||||||||||
212 | * @throws InvalidFontSizeException |
||||||||||
213 | */ |
||||||||||
214 | public |
||||||||||
215 | function setFontSize(int $size) |
||||||||||
216 | { |
||||||||||
217 | if ($size < 1 || $size > 20) |
||||||||||
218 | throw new InvalidFontSizeException(); |
||||||||||
219 | $this->fontSizeInPercents = $size; |
||||||||||
220 | return $this; |
||||||||||
221 | } |
||||||||||
222 | |||||||||||
223 | /** |
||||||||||
224 | * @param int $percent |
||||||||||
225 | * @return Imagenator |
||||||||||
226 | * @throws InvalidPositionValueException |
||||||||||
227 | */ |
||||||||||
228 | public |
||||||||||
229 | function setPadding(int $percent) |
||||||||||
230 | { |
||||||||||
231 | if ($percent < 1 || $percent > 100) |
||||||||||
232 | throw new InvalidPositionValueException(); |
||||||||||
233 | $this->paddingLeftRightInPercents = $percent; |
||||||||||
234 | return $this; |
||||||||||
235 | } |
||||||||||
236 | |||||||||||
237 | /** |
||||||||||
238 | * @param int $percent |
||||||||||
239 | * @return Imagenator |
||||||||||
240 | * @throws InvalidPositionValueException |
||||||||||
241 | */ |
||||||||||
242 | public function setMarginTopInPercents(int $percent) |
||||||||||
243 | { |
||||||||||
244 | if ($percent < 1 || $percent > 100) |
||||||||||
245 | throw new InvalidPositionValueException(); |
||||||||||
246 | $this->marginTopInPercents = $percent; |
||||||||||
247 | return $this; |
||||||||||
248 | } |
||||||||||
249 | |||||||||||
250 | /** |
||||||||||
251 | * @param int $percent |
||||||||||
252 | * @return Imagenator |
||||||||||
253 | * @throws InvalidRowHeightException |
||||||||||
254 | */ |
||||||||||
255 | public |
||||||||||
256 | function setRowHeight(int $percent) |
||||||||||
257 | { |
||||||||||
258 | if ($percent < 1 || $percent > 30) |
||||||||||
259 | throw new InvalidRowHeightException(); |
||||||||||
260 | $this->rowHeight = $percent; |
||||||||||
261 | return $this; |
||||||||||
262 | } |
||||||||||
263 | } |
||||||||||
264 |