Completed
Push — master ( 32e735...6d3dea )
by Evgenii
07:23
created

Imagenator::calculateParams()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 4
c 0
b 0
f 0
dl 0
loc 6
rs 10
cc 1
nc 1
nop 0
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
use floor12\imagenator\exception\InvalidWordPerPageException;
12
13
class Imagenator
14
{
15
    const DEFAULT_IMAGE = __DIR__ . '/../assets/default.png';
16
    /**
17
     * @var string Path to TTF font file
18
     */
19
    protected $font = __DIR__ . '/../assets/Rubik.ttf';
20
    /**
21
     * @var string
22
     */
23
    protected $text = "Dont forget to put some text here :-)";
24
    /**
25
     * @var false|resource
26
     */
27
    protected $image;
28
    /**
29
     * @var int
30
     */
31
    protected $imageWidth;
32
    /**
33
     * @var int
34
     */
35
    protected $imageHeight;
36
    /**
37
     * @var int
38
     */
39
    protected $rowHeight = 8;
40
    /**
41
     * @var int
42
     */
43
    protected $marginTopInPercents = 50;
44
    /**
45
     * @var int
46
     */
47
    protected $paddingLeftRightInPercents = 5;
48
    /**
49
     * @var int Default color is white
50
     */
51
    private $textColor = '16777215';
52
    /**
53
     * @var int
54
     */
55
    private $fontSizeInPercents = 5;
56
    /**
57
     * @var array
58
     */
59
    private $rows = [];
60
    /**
61
     * @var float|int
62
     */
63
    private $positionX;
64
    /**
65
     * @var float|int
66
     */
67
    private $positionStartY;
68
    /**
69
     * @var float|int
70
     */
71
    private $rowHeightInPx;
72
    /**
73
     * @var float|int
74
     */
75
    private $fontSizeInPx;
76
77
    /**
78
     * Imagenator constructor.
79
     * @param string $backgroundImagePath
80
     * @throws ImageNotFoundException
81
     */
82
    public function __construct(string $backgroundImagePath = self::DEFAULT_IMAGE)
83
    {
84
        $this->loadImage($backgroundImagePath);
85
    }
86
87
    /**
88
     * @param string $backgroundImagePath
89
     * @throws ImageNotFoundException
90
     */
91
    protected function loadImage(string $backgroundImagePath)
92
    {
93
        if (!file_exists($backgroundImagePath))
94
            throw new ImageNotFoundException();
95
        $this->image = imagecreatefrompng($backgroundImagePath);
96
        list($this->imageWidth, $this->imageHeight) = getimagesize($backgroundImagePath);
97
    }
98
99
    /**
100
     * @param string $resultImagePath
101
     * @return bool
102
     * @throws FontNotFoundException
103
     */
104
    public function generate(string $resultImagePath): bool
105
    {
106
        $this->calculateParams();
107
        $this->prepareRows();
108
        $this->putRowsToImage();
109
        return $this->saveImage($resultImagePath);
110
    }
111
112
    /**
113
     * @param string $pathToSave
114
     * @return bool
115
     */
116
    protected function saveImage(string $pathToSave): bool
117
    {
118
        return imagepng($this->image, $pathToSave) && imagedestroy($this->image);
0 ignored issues
show
Bug introduced by
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 ignore-type  annotation

118
        return imagepng($this->image, $pathToSave) && imagedestroy(/** @scrutinizer ignore-type */ $this->image);
Loading history...
Bug introduced by
It seems like $this->image can also be of type boolean; however, parameter $image of imagepng() 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

118
        return imagepng(/** @scrutinizer ignore-type */ $this->image, $pathToSave) && imagedestroy($this->image);
Loading history...
119
    }
120
121
    protected function calculateParams()
122
    {
123
        $this->positionStartY = $this->imageHeight / 100 * $this->marginTopInPercents;
124
        $this->rowHeightInPx = $this->imageHeight / 100 * $this->rowHeight;
125
        $this->fontSizeInPx = $this->imageHeight / 100 * $this->fontSizeInPercents;
126
        $this->positionX = $this->imageWidth / 100 * $this->paddingLeftRightInPercents;
127
    }
128
129
    /**
130
     * @throws FontNotFoundException
131
     */
132
    protected function prepareRows(): void
133
    {
134
        if (!file_exists($this->font))
135
            throw new FontNotFoundException();
136
137
        $wordsArray = explode(' ', $this->text);
138
        $validRowWidth = $this->imageWidth - $this->positionX * 2;
139
        $currentRow = 0;
140
141
        foreach ($wordsArray as $word) {
142
            $testRow = isset($this->rows[$currentRow]) ? array_merge($this->rows[$currentRow], [$word]) : [$word];
143
            $imageBox = imagettfbbox($this->fontSizeInPx, 0, $this->font, implode('', $testRow));
144
            if ($imageBox[2] >= $validRowWidth) {
145
                $lastWord = end($this->rows[$currentRow]);
146
                if (mb_strlen($lastWord) <= 2) {
147
                    $this->rows[$currentRow + 1][] = array_pop($this->rows[$currentRow]);
148
                }
149
                $this->rows[++$currentRow][] = $word;
150
            } else {
151
                $this->rows[$currentRow][] = $word;
152
            }
153
        }
154
    }
155
156
    /**
157
     *
158
     */
159
    protected function putRowsToImage()
160
    {
161
        foreach ($this->rows as $rowNumber => $row) {
162
            $string = implode(' ', $row);
163
            $positionY = $this->positionStartY + ($rowNumber * $this->rowHeightInPx);
164
            imagettftext($this->image, $this->fontSizeInPx, 0, $this->positionX, $positionY, $this->textColor, $this->font, $string);
0 ignored issues
show
Bug introduced by
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 ignore-type  annotation

164
            imagettftext($this->image, $this->fontSizeInPx, 0, /** @scrutinizer ignore-type */ $this->positionX, $positionY, $this->textColor, $this->font, $string);
Loading history...
Bug introduced by
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 ignore-type  annotation

164
            imagettftext(/** @scrutinizer ignore-type */ $this->image, $this->fontSizeInPx, 0, $this->positionX, $positionY, $this->textColor, $this->font, $string);
Loading history...
Bug introduced by
$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 ignore-type  annotation

164
            imagettftext($this->image, $this->fontSizeInPx, 0, $this->positionX, /** @scrutinizer ignore-type */ $positionY, $this->textColor, $this->font, $string);
Loading history...
165
        }
166
    }
167
168
    /**
169
     * @param string $text
170
     * @return self
171
     */
172
    public
173
    function setText(string $text): self
174
    {
175
        $this->text = $text;
176
        return $this;
177
    }
178
179
    /**
180
     * @param string $font
181
     * @return self
182
     */
183
    public
184
    function setFont(string $font): self
185
    {
186
        $this->font = $font;
187
        return $this;
188
    }
189
190
    /**
191
     * @param string $colorInHex
192
     * @return self
193
     * @throws InvalidHexColorException
194
     */
195
    public
196
    function setColor(string $colorInHex): self
197
    {
198
        $colorInHex = str_replace('#', '', $colorInHex);
199
200
        if (!ctype_xdigit($colorInHex) || strlen($colorInHex) !== 6)
201
            throw new InvalidHexColorException();
202
203
        $red = hexdec(substr($colorInHex, 0, 2));
204
        $green = hexdec(substr($colorInHex, 2, 2));
205
        $blue = hexdec(substr($colorInHex, 4, 2));
206
        $this->textColor = imagecolorallocate($this->image, $red, $green, $blue);
0 ignored issues
show
Bug introduced by
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 ignore-type  annotation

206
        $this->textColor = imagecolorallocate($this->image, $red, $green, /** @scrutinizer ignore-type */ $blue);
Loading history...
Bug introduced by
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 ignore-type  annotation

206
        $this->textColor = imagecolorallocate($this->image, $red, /** @scrutinizer ignore-type */ $green, $blue);
Loading history...
Bug introduced by
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 ignore-type  annotation

206
        $this->textColor = imagecolorallocate($this->image, /** @scrutinizer ignore-type */ $red, $green, $blue);
Loading history...
Bug introduced by
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 ignore-type  annotation

206
        $this->textColor = imagecolorallocate(/** @scrutinizer ignore-type */ $this->image, $red, $green, $blue);
Loading history...
207
        return $this;
208
    }
209
210
    /**
211
     * @param int $size
212
     * @return Imagenator
213
     * @throws InvalidFontSizeException
214
     */
215
    public
216
    function setFontSize(int $size)
217
    {
218
        if ($size < 1 || $size > 20)
219
            throw new InvalidFontSizeException();
220
        $this->fontSizeInPercents = $size;
221
        return $this;
222
    }
223
224
    /**
225
     * @param int $wordsPerRow
226
     * @return Imagenator
227
     * @throws InvalidWordPerPageException
228
     */
229
    public
230
    function setWordsPerRow(int $wordsPerRow)
231
    {
232
        if ($wordsPerRow < 1 || $wordsPerRow > 30)
233
            throw new InvalidWordPerPageException();
234
        $this->wordsPerRow = $wordsPerRow;
0 ignored issues
show
Bug Best Practice introduced by
The property wordsPerRow does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
235
        return $this;
236
    }
237
238
    /**
239
     * @param int $percent
240
     * @return Imagenator
241
     * @throws InvalidPositionValueException
242
     */
243
    public
244
    function setPadding(int $percent)
245
    {
246
        if ($percent < 1 || $percent > 100)
247
            throw new InvalidPositionValueException();
248
        $this->paddingLeftRightInPercents = $percent;
249
        return $this;
250
    }
251
252
    /**
253
     * @param int $percent
254
     * @return Imagenator
255
     * @throws InvalidPositionValueException
256
     */
257
    public function setMarginTopInPercents(int $percent)
258
    {
259
        if ($percent < 1 || $percent > 100)
260
            throw new InvalidPositionValueException();
261
        $this->marginTopInPercents = $percent;
262
        return $this;
263
    }
264
265
    /**
266
     * @param int $percent
267
     * @return Imagenator
268
     * @throws InvalidRowHeightException
269
     */
270
    public
271
    function setRowHeight(int $percent)
272
    {
273
        if ($percent < 1 || $percent > 30)
274
            throw new InvalidRowHeightException();
275
        $this->rowHeight = $percent;
276
        return $this;
277
    }
278
}
279