Completed
Push — master ( 53bf76...32e735 )
by Evgenii
01:30
created

Imagenator::putTextToImage()   B

Complexity

Conditions 6
Paths 6

Size

Total Lines 30
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 1
Metric Value
eloc 21
c 2
b 0
f 1
dl 0
loc 30
rs 8.9617
cc 6
nc 6
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 as InvalidFontSizeExceptionAlias;
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 $wordsPerRow = 7;
40
    /**
41
     * @var int
42
     */
43
    protected $rowHeight = 8;
44
    /**
45
     * @var int
46
     */
47
    protected $textPositionPercentY = 50;
48
    /**
49
     * @var int
50
     */
51
    protected $textPositionPercentX = 5;
52
    /**
53
     * @var int Default color is white
54
     */
55
    private $textColor = '16777215';
56
    /**
57
     * @var int
58
     */
59
    private $fontSizeInPercents = 5;
60
61
    /**
62
     * Imagenator constructor.
63
     * @param string $backgroundImagePath
64
     * @throws ImageNotFoundException
65
     */
66
    public function __construct(string $backgroundImagePath = self::DEFAULT_IMAGE)
67
    {
68
        $this->loadImage($backgroundImagePath);
69
    }
70
71
    /**
72
     * @param string $backgroundImagePath
73
     * @throws ImageNotFoundException
74
     */
75
    protected function loadImage(string $backgroundImagePath)
76
    {
77
        if (!file_exists($backgroundImagePath))
78
            throw new ImageNotFoundException();
79
        $this->image = imagecreatefrompng($backgroundImagePath);
80
        list($this->imageWidth, $this->imageHeight) = getimagesize($backgroundImagePath);
81
    }
82
83
    /**
84
     * @param string $resultImagePath
85
     * @return bool
86
     * @throws FontNotFoundException
87
     */
88
    public function generate(string $resultImagePath): bool
89
    {
90
        $this->putTextToImage();
91
        return $this->saveImage($resultImagePath);
92
    }
93
94
    /**
95
     * @param string $pathToSave
96
     * @return bool
97
     */
98
    protected function saveImage(string $pathToSave): bool
99
    {
100
        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 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

100
        return imagepng(/** @scrutinizer ignore-type */ $this->image, $pathToSave) && imagedestroy($this->image);
Loading history...
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

100
        return imagepng($this->image, $pathToSave) && imagedestroy(/** @scrutinizer ignore-type */ $this->image);
Loading history...
101
    }
102
103
    /**
104
     * @throws FontNotFoundException
105
     */
106
    protected function putTextToImage(): void
107
    {
108
        if (!file_exists($this->font))
109
            throw new FontNotFoundException();
110
111
        $wordsArray = explode(' ', $this->text);
112
        $rows = array_chunk($wordsArray, $this->wordsPerRow);
113
        $positionStartY = $this->imageHeight / 100 * $this->textPositionPercentY;
114
        $rowHeightInPx = $this->imageHeight / 100 * $this->rowHeight;
115
        $fontSizeInPx = $this->imageHeight / 100 * $this->fontSizeInPercents;
116
        $positionX = $this->imageWidth / 100 * $this->textPositionPercentX;
117
        $lastRowNumber = sizeof($rows) - 1;
118
        $wordToWrap = '';
119
120
        foreach ($rows as $stringNumber => $wordsArray) {
121
            $lastWordInRow = $wordsArray[sizeof($wordsArray) - 1];
122
            $lastWordInRowLength = strlen($lastWordInRow);
123
124
            if (!empty($wordToWrap)) {
125
                array_unshift($wordsArray, $wordToWrap);
126
                $wordToWrap = '';
127
            }
128
129
            if ($lastWordInRowLength <= 2 && $stringNumber != $lastRowNumber) {
130
                $wordToWrap = array_pop($wordsArray);
131
            }
132
133
            $string = implode(' ', $wordsArray);
134
            $positionY = $positionStartY + $stringNumber * $rowHeightInPx;
135
            imagettftext($this->image, $fontSizeInPx, 0, $positionX, $positionY, $this->textColor, $this->font, $string);
0 ignored issues
show
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

135
            imagettftext(/** @scrutinizer ignore-type */ $this->image, $fontSizeInPx, 0, $positionX, $positionY, $this->textColor, $this->font, $string);
Loading history...
136
        }
137
138
    }
139
140
    /**
141
     * @param string $text
142
     * @return self
143
     */
144
    public function setText(string $text): self
145
    {
146
        $this->text = $text;
147
        return $this;
148
    }
149
150
    /**
151
     * @param string $font
152
     * @return self
153
     */
154
    public function setFont(string $font): self
155
    {
156
        $this->font = $font;
157
        return $this;
158
    }
159
160
    /**
161
     * @param string $colorInHex
162
     * @return self
163
     * @throws InvalidHexColorException
164
     */
165
    public function setColor(string $colorInHex): self
166
    {
167
        $colorInHex = str_replace('#', '', $colorInHex);
168
169
        if (!ctype_xdigit($colorInHex) || strlen($colorInHex) !== 6)
170
            throw new InvalidHexColorException();
171
172
        $red = hexdec(substr($colorInHex, 0, 2));
173
        $green = hexdec(substr($colorInHex, 2, 2));
174
        $blue = hexdec(substr($colorInHex, 4, 2));
175
        $this->textColor = imagecolorallocate($this->image, $red, $green, $blue);
0 ignored issues
show
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

175
        $this->textColor = imagecolorallocate(/** @scrutinizer ignore-type */ $this->image, $red, $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

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

175
        $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

175
        $this->textColor = imagecolorallocate($this->image, $red, /** @scrutinizer ignore-type */ $green, $blue);
Loading history...
176
        return $this;
177
    }
178
179
    /**
180
     * @param int $size
181
     * @return Imagenator
182
     * @throws InvalidFontSizeExceptionAlias
183
     */
184
    public function setFontSize(int $size)
185
    {
186
        if ($size < 1 || $size > 20)
187
            throw new InvalidFontSizeExceptionAlias();
188
        $this->fontSizeInPercents = $size;
189
        return $this;
190
    }
191
192
    /**
193
     * @param int $wordsPerRow
194
     * @return Imagenator
195
     * @throws InvalidWordPerPageException
196
     */
197
    public function setWordsPerRow(int $wordsPerRow)
198
    {
199
        if ($wordsPerRow < 1 || $wordsPerRow > 30)
200
            throw new InvalidWordPerPageException();
201
        $this->wordsPerRow = $wordsPerRow;
202
        return $this;
203
    }
204
205
    /**
206
     * @param int $percent
207
     * @return Imagenator
208
     * @throws InvalidPositionValueException
209
     */
210
    public function setPositionX(int $percent)
211
    {
212
        if ($percent < 1 || $percent > 100)
213
            throw new InvalidPositionValueException();
214
        $this->textPositionPercentX = $percent;
215
        return $this;
216
    }
217
218
    /**
219
     * @param int $percent
220
     * @return Imagenator
221
     * @throws InvalidPositionValueException
222
     */
223
    public function setPositionY(int $percent)
224
    {
225
        if ($percent < 1 || $percent > 100)
226
            throw new InvalidPositionValueException();
227
        $this->textPositionPercentY = $percent;
228
        return $this;
229
    }
230
231
    /**
232
     * @param int $percent
233
     * @return Imagenator
234
     * @throws InvalidRowHeightException
235
     */
236
    public function setRowHeight(int $percent)
237
    {
238
        if ($percent < 1 || $percent > 30)
239
            throw new InvalidRowHeightException();
240
        $this->rowHeight = $percent;
241
        return $this;
242
    }
243
}
244