]> scripts.mit.edu Git - autoinstalls/mediawiki.git/blob - vendor/stil/gd-text/src/Box.php
MediaWiki 1.30.2
[autoinstalls/mediawiki.git] / vendor / stil / gd-text / src / Box.php
1 <?php
2 namespace GDText;
3
4 class Box
5 {
6     /**
7      * @var resource
8      */
9     protected $im;
10
11     /**
12      * @var int
13      */
14     protected $fontSize = 12;
15
16     /**
17      * @var Color
18      */
19     protected $fontColor;
20
21     /**
22      * @var string
23      */
24     protected $alignX = 'left';
25
26     /**
27      * @var string
28      */
29     protected $alignY = 'top';
30
31     /**
32      * @var float
33      */
34     protected $lineHeight = 1.25;
35
36     /**
37      * @var float
38      */
39     protected $baseline = 0.2;
40
41     /**
42      * @var string
43      */
44     protected $fontFace = null;
45
46     /**
47      * @var bool
48      */
49     protected $debug = false;
50
51     /**
52      * @var bool|array
53      */
54     protected $textShadow = false;
55
56     /**
57      * @var array
58      */
59     protected $box = array(
60         'x' => 0,
61         'y' => 0,
62         'width' => 100,
63         'height' => 100
64     );
65
66     public function __construct(&$image)
67     {
68         $this->im = $image;
69         $this->fontColor = new Color(0, 0, 0);
70     }
71
72     /**
73      * @param Color $color Font color
74      */
75     public function setFontColor(Color $color)
76     {
77         $this->fontColor = $color;
78     }
79
80     /**
81      * @param string $path Path to the font file
82      */
83     public function setFontFace($path)
84     {
85         $this->fontFace = $path;
86     }
87
88     /**
89      * @param int $v Font size in *pixels*
90      */
91     public function setFontSize($v)
92     {
93         $this->fontSize = $v;
94     }
95
96     /**
97      * @param Color $color Shadow color
98      * @param int $xShift Relative shadow position in pixels. Positive values move shadow to right, negative to left.
99      * @param int $yShift Relative shadow position in pixels. Positive values move shadow to bottom, negative to up.
100      */
101     public function setTextShadow(Color $color, $xShift, $yShift)
102     {
103         $this->textShadow = array(
104             'color' => $color,
105             'x' => $xShift,
106             'y' => $yShift
107         );
108     }
109
110     /**
111      * Allows to customize spacing between lines.
112      * @param float $v Height of the single text line, in percents, proportionally to font size
113      */
114     public function setLineHeight($v)
115     {
116         $this->lineHeight = $v;
117     }
118
119     /**
120      * @param float $v Position of baseline, in percents, proportionally to line height measuring from the bottom.
121      */
122     public function setBaseline($v)
123     {
124         $this->baseline = $v;
125     }
126
127     /**
128      * Sets text alignment inside textbox
129      * @param string $x Horizontal alignment. Allowed values are: left, center, right.
130      * @param string $y Vertical alignment. Allowed values are: top, center, bottom.
131      */
132     public function setTextAlign($x = 'left', $y = 'top')
133     {
134         $xAllowed = array('left', 'right', 'center');
135         $yAllowed = array('top', 'bottom', 'center');
136
137         if (!in_array($x, $xAllowed)) {
138             throw new \InvalidArgumentException('Invalid horizontal alignement value was specified.');
139         }
140
141         if (!in_array($y, $yAllowed)) {
142             throw new \InvalidArgumentException('Invalid vertical alignement value was specified.');
143         }
144
145         $this->alignX = $x;
146         $this->alignY = $y;
147     }
148
149     /**
150      * Sets textbox position and dimensions
151      * @param int $x Distance in pixels from left edge of image.
152      * @param int $y Distance in pixels from top edge of image.
153      * @param int $width Width of texbox in pixels.
154      * @param int $height Height of textbox in pixels.
155      */
156     public function setBox($x, $y, $width, $height)
157     {
158         $this->box['x'] = $x;
159         $this->box['y'] = $y;
160         $this->box['width'] = $width;
161         $this->box['height'] = $height;
162     }
163
164     /**
165      * Enables debug mode. Whole textbox and individual lines will be filled with random colors.
166      */
167     public function enableDebug()
168     {
169         $this->debug = true;
170     }
171
172     /**
173      * Draws the text on the picture.
174      * @param string $text Text to draw. May contain newline characters.
175      */
176     public function draw($text)
177     {
178         if (!isset($this->fontFace)) {
179             throw new \InvalidArgumentException('No path to font file has been specified.');
180         }
181
182         $lines = array();
183         // Split text explicitly into lines by \n, \r\n and \r
184         $explicitLines = preg_split('/\n|\r\n?/', $text);
185         foreach ($explicitLines as $line) {
186             // Check every line if it needs to be wrapped
187             $words = explode(" ", $line);
188             $line = $words[0];
189             for ($i = 1; $i < count($words); $i++) {
190                 $box = $this->calculateBox($line." ".$words[$i]);
191                 if (($box[4]-$box[6]) >= $this->box['width']) {
192                     $lines[] = $line;
193                     $line = $words[$i];
194                 } else {
195                     $line .= " ".$words[$i];
196                 }
197             }
198             $lines[] = $line;
199         }
200
201         if ($this->debug) {
202             // Marks whole texbox area with color
203             $this->drawFilledRectangle(
204                 $this->box['x'],
205                 $this->box['y'],
206                 $this->box['width'],
207                 $this->box['height'],
208                 new Color(rand(180, 255), rand(180, 255), rand(180, 255), 80)
209             );
210         }
211
212         $lineHeightPx = $this->lineHeight * $this->fontSize;
213         $textHeight = count($lines) * $lineHeightPx;
214         
215         switch ($this->alignY) {
216             case 'center':
217                 $yAlign = ($this->box['height'] / 2) - ($textHeight / 2);
218                 break;
219             case 'bottom':
220                 $yAlign = $this->box['height'] - $textHeight;
221                 break;
222             case 'top':
223             default:
224                 $yAlign = 0;
225         }
226         
227         $n = 0;
228         foreach ($lines as $line) {
229             $box = $this->calculateBox($line);
230             $boxWidth = $box[2] - $box[0];
231             switch ($this->alignX) {
232                 case 'center':
233                     $xAlign = ($this->box['width'] - $boxWidth) / 2;
234                     break;
235                 case 'right':
236                     $xAlign = ($this->box['width'] - $boxWidth);
237                     break;
238                 case 'left':
239                 default:
240                     $xAlign = 0;
241             }
242             $yShift = $lineHeightPx * (1 - $this->baseline);
243
244             // current line X and Y position
245             $xMOD = $this->box['x'] + $xAlign;
246             $yMOD = $this->box['y'] + $yAlign + $yShift + ($n * $lineHeightPx);
247             
248             if ($this->debug) {
249                 // Marks current line with color
250                 $this->drawFilledRectangle(
251                     $xMOD,
252                     $this->box['y'] + $yAlign + ($n * $lineHeightPx),
253                     $boxWidth,
254                     $lineHeightPx,
255                     new Color(rand(1, 180), rand(1, 180), rand(1, 180))
256                 );
257             }
258             
259             if ($this->textShadow !== false) {
260                 $this->drawInternal(
261                     $xMOD + $this->textShadow['x'],
262                     $yMOD + $this->textShadow['y'],
263                     $this->textShadow['color'],
264                     $line
265                 );
266             }
267
268             $this->drawInternal(
269                 $xMOD,
270                 $yMOD,
271                 $this->fontColor,
272                 $line
273             );
274
275             $n++;
276         }
277     }
278
279     protected function getFontSizeInPoints()
280     {
281         return 0.75 * $this->fontSize;
282     }
283
284     protected function drawFilledRectangle($x, $y, $width, $height, Color $color)
285     {
286         imagefilledrectangle($this->im, $x, $y, $x + $width, $y + $height,
287             $color->getIndex($this->im)
288         );
289     }
290
291     protected function calculateBox($text)
292     {
293         return imageftbbox($this->getFontSizeInPoints(), 0, $this->fontFace, $text);
294     }
295
296     protected function drawInternal($x, $y, Color $color, $text)
297     {
298         imagefttext(
299             $this->im,
300             $this->getFontSizeInPoints(),
301             0, // no rotation
302             $x,
303             $y,
304             $color->getIndex($this->im),
305             $this->fontFace,
306             $text
307         );
308     }
309 }