1<?php
2/***************************************************************************
3 *   copyright            : (C) 2005 by Pascal Brachet - France            *
4 *   pbrachet_NOSPAM_xm1math.net (replace _NOSPAM_ by @)                   *
5 *   http://www.xm1math.net/phpmathpublisher/                              *
6 *                                                                         *
7 *   This program is free software; you can redistribute it and/or modify  *
8 *   it under the terms of the GNU General Public License as published by  *
9 *   the Free Software Foundation; either version 2 of the License, or     *
10 *   (at your option) any later version.                                   *
11 *                                                                         *
12 ***************************************************************************/
13
14namespace RL\PhpMathPublisher;
15
16/**
17 * \RL\PhpMathPublisher\Helper
18 *
19 * @author Pascal Brachet <pbrachet@xm1math.net>
20 * @author Peter Vasilevsky <tuxoiduser@gmail.com> a.k.a. Tux-oid
21 * @license GPLv2
22 */
23class Helper
24{
25
26    /**
27     * @var string
28     */
29    public $dirFonts;
30    /**
31     * @var string
32     */
33    public $dirImg;
34    /**
35     * @var int
36     */
37    public $backR;
38    /**
39     * @var int
40     */
41    public $backG;
42    /**
43     * @var int
44     */
45    public $backB;
46    /**
47     * @var int
48     */
49    public $fontR;
50    /**
51     * @var int
52     */
53    public $fontG;
54    /**
55     * @var int
56     */
57    public $fontB;
58    /**
59     * @var bool
60     */
61    public $transparent;
62    /**
63     * @var array
64     */
65    public $symbols;
66    /**
67     * @var array
68     */
69    public $mathFonts;
70
71    /**
72     * Constructor
73     */
74    public function __construct()
75    {
76        $this->dirFonts = __DIR__ . "/fonts";
77        $this->dirImg = __DIR__ . "/images";
78        $this->backR = 255;
79        $this->backG = 255;
80        $this->backB = 255;
81        $this->fontR = 0;
82        $this->fontG = 0;
83        $this->fontB = 0;
84        $this->transparent = false;
85        $this->symbols = array(
86            '~' => ' ',
87            'alpha' => '&#174;',
88            'beta' => '&#175;',
89            'gamma' => '&#176;',
90            'delta' => '&#177;',
91            'epsilon' => '&#178;',
92            'varepsilon' => '&#34;',
93            'zeta' => '&#179;',
94            'eta' => '&#180;',
95            'theta' => '&#181;',
96            'vartheta' => '&#35;',
97            'iota' => '&#182;',
98            'kappa' => '&#183;',
99            'lambda' => '&#184;',
100            'mu' => '&#185;',
101            'nu' => '&#186;',
102            'xi' => '&#187;',
103            'pi' => '&#188;',
104            'varpi' => '&#36;',
105            'rho' => '&#189;',
106            'varrho' => '&#37;',
107            'sigma' => '&#190;',
108            'varsigma' => '&#38;',
109            'tau' => '&#191;',
110            'upsilon' => '&#192;',
111            'phi' => '&#193;',
112            'varphi' => '&#39;',
113            'chi' => '&#194;',
114            'psi' => '&#195;',
115            'omega' => '&#33;',
116            'Gamma' => '&#161;',
117            'Lambda' => '&#164;',
118            'Sigma' => '&#167;',
119            'Psi' => '&#170;',
120            'Delta' => '&#162;',
121            'Xi' => '&#165;',
122            'Upsilon' => '&#168;',
123            'Omega' => '&#173;',
124            'Theta' => '&#163;',
125            'Pi' => '&#166;',
126            'Phi' => '&#169;',
127            'infty' => '&#8734;',
128            'ne' => '&#8800;',
129            '*' => '&#215;',
130            'in' => '&#8712;',
131            'notin' => '&#8713;',
132            'forall' => '&#8704;',
133            'exists' => '&#8707;',
134            'notexists' => '&#8708;',
135            'partial' => '&#8706;',
136            'approx' => '&#8776;',
137            'left' => '&#8592;',
138            'right' => '&#8594;',
139            'leftright' => '&#8596;',
140            'doubleleft' => '&#8656;',
141            'doubleright' => '&#8658;',
142            'doubleleftright' => '&#8660;',
143            'nearrow' => '&#8599;',
144            'searrow' => '&#8601;',
145            'pm' => '&#177;',
146            'bbR' => '&#8477;',
147            'bbN' => '&#8469;',
148            'bbZ' => '&#8484;',
149            'bbC' => '&#8450;',
150            'inter' => '&#8898;',
151            'union' => '&#8899;',
152            'ortho' => '&#8869;',
153            'parallel' => '&#8741;',
154            'backslash' => '&#92;',
155            'prime' => '&#39;',
156            'wedge' => '&#8896;',
157            'vert' => '&#8741;',
158            'subset' => '&#8834;',
159            'notsubset' => '&#8836;',
160            'circ' => '&#8728;',
161            'varnothing' => '&#248;',
162            'cdots' => '&#8943;',
163            'vdots' => '&#8942;',
164            'ddots' => '&#8945;', //operateurs
165            'le' => '&#54;',
166            'ge' => '&#62;',
167            '<' => '&#60;',
168            '>' => '&#62;', //parentheses
169            '(' => '&#179;',
170            ')' => '&#180;',
171            '[' => '&#104;',
172            ']' => '&#105;',
173            'lbrace' => '&#40;',
174            'rbrace' => '&#41;', //autres
175            '_hat' => '&#99;',
176            '_racine' => '&#113;',
177            '_integrale' => '&#82;',
178            '_dintegrale' => '&#8748;',
179            '_tintegrale' => '&#8749;',
180            '_ointegrale' => '&#72;',
181            '_produit' => '&#81;',
182            '_somme' => '&#80;',
183            '_intersection' => '&#84;',
184            '_reunion' => '&#83;',
185            '_lim' => 'lim', //fonctions
186            'arccos' => 'arccos',
187            'ker' => 'ker',
188            'arcsin' => 'arcsin',
189            'lg' => 'lg',
190            'arctan' => 'arctan',
191            'arg' => 'arg',
192            'cos' => 'cos',
193            'cosh' => 'cosh',
194            'ln' => 'ln',
195            'cot' => 'cot',
196            'log' => 'log',
197            'coth' => 'coth',
198            'max' => 'max',
199            'csc' => 'csc',
200            'min' => 'min',
201            'deg' => 'deg',
202            'det' => 'det',
203            'sec' => 'sec',
204            'dim' => 'dim',
205            'sin' => 'sin',
206            'exp' => 'exp',
207            'sinh' => 'sinh',
208            'gcd' => 'gcd',
209            'sup' => 'sup',
210            'hom' => 'hom',
211            'tan' => 'tan',
212            'inf' => 'inf',
213            'tanh' => 'tanh',
214        );
215        $this->mathFonts = array(
216            '~' => 'FreeSerif',
217            'alpha' => 'cmmi10',
218            'beta' => 'cmmi10',
219            'gamma' => 'cmmi10',
220            'delta' => 'cmmi10',
221            'epsilon' => 'cmmi10',
222            'varepsilon' => 'cmmi10',
223            'zeta' => 'cmmi10',
224            'eta' => 'cmmi10',
225            'theta' => 'cmmi10',
226            'vartheta' => 'cmmi10',
227            'iota' => 'cmmi10',
228            'kappa' => 'cmmi10',
229            'lambda' => 'cmmi10',
230            'mu' => 'cmmi10',
231            'nu' => 'cmmi10',
232            'xi' => 'cmmi10',
233            'pi' => 'cmmi10',
234            'varpi' => 'cmmi10',
235            'rho' => 'cmmi10',
236            'varrho' => 'cmmi10',
237            'sigma' => 'cmmi10',
238            'varsigma' => 'cmmi10',
239            'tau' => 'cmmi10',
240            'upsilon' => 'cmmi10',
241            'phi' => 'cmmi10',
242            'varphi' => 'cmmi10',
243            'chi' => 'cmmi10',
244            'psi' => 'cmmi10',
245            'omega' => 'cmmi10',
246            'Gamma' => 'cmr10',
247            'Lambda' => 'cmr10',
248            'Sigma' => 'cmr10',
249            'Psi' => 'cmr10',
250            'Delta' => 'cmr10',
251            'Xi' => 'cmr10',
252            'Upsilon' => 'cmr10',
253            'Omega' => 'cmr10',
254            'Theta' => 'cmr10',
255            'Pi' => 'cmr10',
256            'Phi' => 'cmr10',
257            'infty' => 'FreeSerif',
258            'ne' => 'FreeSerif',
259            '*' => 'FreeSerif',
260            'in' => 'FreeSerif',
261            'notin' => 'FreeSerif',
262            'forall' => 'FreeSerif',
263            'exists' => 'FreeSerif',
264            'notexists' => 'FreeSerif',
265            'partial' => 'FreeSerif',
266            'approx' => 'FreeSerif',
267            'left' => 'FreeSerif',
268            'right' => 'FreeSerif',
269            'leftright' => 'FreeSerif',
270            'doubleleft' => 'FreeSerif',
271            'doubleright' => 'FreeSerif',
272            'doubleleftright' => 'FreeSerif',
273            'nearrow' => 'FreeSerif',
274            'searrow' => 'FreeSerif',
275            'pm' => 'FreeSerif',
276            'bbR' => 'FreeSerif',
277            'bbN' => 'FreeSerif',
278            'bbZ' => 'FreeSerif',
279            'bbC' => 'FreeSerif',
280            'inter' => 'FreeSerif',
281            'union' => 'FreeSerif',
282            'ortho' => 'FreeSerif',
283            'parallel' => 'FreeSerif',
284            'backslash' => 'FreeSerif',
285            'prime' => 'FreeSerif',
286            'wedge' => 'FreeSerif',
287            'vert' => 'FreeSerif',
288            'subset' => 'FreeSerif',
289            'notsubset' => 'FreeSerif',
290            'circ' => 'FreeSerif',
291            'varnothing' => 'FreeSerif',
292            'cdots' => 'FreeSerif',
293            'vdots' => 'FreeSerif',
294            'ddots' => 'FreeSerif', //operateurs
295            'le' => 'msam10',
296            'ge' => 'msam10',
297            '<' => 'cmmi10',
298            '>' => 'cmmi10', //parentheses
299            '(' => 'cmex10',
300            ')' => 'cmex10',
301            '[' => 'cmex10',
302            ']' => 'cmex10',
303            'lbrace' => 'cmex10',
304            'rbrace' => 'cmex10', //autres
305            '_hat' => 'cmex10',
306            '_racine' => 'cmex10',
307            '_integrale' => 'cmex10',
308            '_dintegrale' => 'FreeSerif',
309            '_tintegrale' => 'FreeSerif',
310            '_ointegrale' => 'cmex10',
311            '_produit' => 'cmex10',
312            '_somme' => 'cmex10',
313            '_intersection' => 'cmex10',
314            '_reunion' => 'cmex10',
315            '_lim' => 'cmr10', //fonctions
316            'arccos' => 'cmr10',
317            'ker' => 'cmr10',
318            'arcsin' => 'cmr10',
319            'lg' => 'cmr10',
320            'arctan' => 'cmr10',
321            'arg' => 'cmr10',
322            'cos' => 'cmr10',
323            'cosh' => 'cmr10',
324            'ln' => 'cmr10',
325            'cot' => 'cmr10',
326            'log' => 'cmr10',
327            'coth' => 'cmr10',
328            'max' => 'cmr10',
329            'csc' => 'cmr10',
330            'min' => 'cmr10',
331            'deg' => 'cmr10',
332            'det' => 'cmr10',
333            'sec' => 'cmr10',
334            'dim' => 'cmr10',
335            'sin' => 'cmr10',
336            'exp' => 'cmr10',
337            'sinh' => 'cmr10',
338            'gcd' => 'cmr10',
339            'sup' => 'cmr10',
340            'hom' => 'cmr10',
341            'tan' => 'cmr10',
342            'inf' => 'cmr10',
343            'tanh' => 'cmr10'
344        );
345
346
347    }
348
349    /**
350     * @param $str
351     * @return int
352     */
353    public function isNumber($str)
354    {
355        return preg_match("#^[0-9]#", $str);
356    }
357
358    /**
359     * @param $expression
360     * @return array
361     */
362    public function tableExpression($expression)
363    {
364        $e = str_replace('_', ' _ ', $expression);
365        $e = str_replace('{(}', '{ }', $e);
366        $e = str_replace('{)}', '{ }', $e);
367        $t = token_get_all("<?php \$formula=$e ?" . ">");
368        $extracts = array();
369        $result = array();
370        //stupid code but token_get_all bug in some php versions
371        $d = 0;
372        for ($i = 0; $i < count($t); $i++) {
373            if (is_array($t[$i])) {
374                $t[$i] = $t[$i][1];
375            }
376            if (preg_match("#formula#", $t[$i])) {
377                $d = $i + 2;
378                break;
379            }
380        }
381        for ($i = $d; $i < count($t) - 1; $i++) {
382            if (is_array($t[$i])) {
383                $t[$i] = $t[$i][1];
384            }
385            if ($t[$i] == '<=') {
386                $t[$i] = 'le';
387            } elseif ($t[$i] == '!=') {
388                $t[$i] = 'ne';
389            } elseif ($t[$i] == '<>') {
390                $t[$i] = 'ne';
391            } elseif ($t[$i] == '>=') {
392                $t[$i] = 'ge';
393            } elseif ($t[$i] == '--') {
394                $t[$i] = '-';
395                $t[$i + 1] = '-' . $t[$i + 1];
396            } elseif ($t[$i] == '++') {
397                $t[$i] = '+';
398            } elseif ($t[$i] == '-') {
399                if ($t[$i - 1] == '^' || $t[$i - 1] == '_' || $t[$i - 1] == '*' || $t[$i - 1] == '/' || $t[$i - 1] == '+' || $t[$i - 1] == '(') {
400                    $t[$i] = '';
401                    if (is_array($t[$i + 1])) {
402                        $t[$i + 1][1] = '-' . $t[$i + 1][1];
403                    } else {
404                        $t[$i + 1] = '-' . $t[$i + 1];
405                    }
406                }
407            }
408            if (trim($t[$i]) != '') {
409                $extracts[] = $t[$i];
410            }
411        }
412        for ($i = 0; $i < count($extracts); $i++) {
413            $result[] = new TextExpression($extracts[$i], $this);
414        }
415
416        return $result;
417    }
418
419    // ugly hack, but GD is not very good with truetype fonts (especially with latex fonts)
420    /**
421     * @param $text
422     * @param $high
423     * @return resource
424     */
425    public function displaySymbol($text, $high)
426    {
427        $symbols = $this->getSymbols();
428        $fontsMath = $this->getMathFonts();
429        $dirFonts = $this->getDirFonts();
430        $text = trim(stripslashes($text));
431        switch ($text) {
432            case '':
433                $img = imagecreate(1, max($high, 1));
434                $white = $this->getBackColor($img);
435                imagefilledrectangle($img, 0, 0, 1, $high, $white);
436                break;
437            case '~':
438                $img = imagecreate(1, max($high, 1));
439                $white = $this->getBackColor($img);
440                imagefilledrectangle($img, 0, 0, 1, $high, $white);
441                break;
442            case 'vert':
443                $img = imagecreate(6, max($high, 1));
444                $black = $this->getFontColor($img);
445                $white = $this->getBackColor($img);
446                imagefilledrectangle($img, 0, 0, 6, $high, $white);
447                imagefilledrectangle($img, 2, 0, 2, $high, $black);
448                imagefilledrectangle($img, 4, 0, 4, $high, $black);
449                break;
450            case '|':
451                $img = imagecreate(5, max($high, 1));
452                $black = $this->getFontColor($img);
453                $white = $this->getBackColor($img);
454                imagefilledrectangle($img, 0, 0, 5, $high, $white);
455                imagefilledrectangle($img, 2, 0, 2, $high, $black);
456                break;
457            case 'right':
458                $font = $dirFonts . "/" . $fontsMath[$text] . ".ttf";
459                $t = 16;
460                $text = $symbols[$text];
461                $tmpDim = imagettfbbox($t, 0, $font, $text);
462                $tmpWidth = abs($tmpDim[2] - $tmpDim[0]) + 2;
463                $tmpHeight = abs($tmpDim[3] - $tmpDim[5]) + 2;
464                $tmpImg = imagecreate(max($tmpWidth, 1), max($tmpHeight, 1));
465                $tmpBlack = $this->getFontColor($tmpImg);
466                $tmpWhite = $this->getBackColor($tmpImg);
467                imagefilledrectangle($tmpImg, 0, 0, $tmpWidth, $tmpHeight, $tmpWhite);
468                imagettftext($tmpImg, $t, 0, 0, $tmpHeight, $tmpBlack, $font, $text);
469                $allWhite = true;
470                $sx = $sy = $ex = $ey = -1;
471                for ($y = 0; $y < $tmpHeight; $y++) {
472                    for ($x = 0; $x < $tmpWidth; $x++) {
473                        $rgb = imagecolorat($tmpImg, $x, $y);
474                        if ($rgb != $tmpWhite) {
475                            $allWhite = false;
476                            if ($sy == -1) {
477                                $sy = $y;
478                            } else {
479                                $ey = $y;
480                            }
481
482                            if ($sx == -1) {
483                                $sx = $x;
484                            } else {
485                                if ($x < $sx) {
486                                    $sx = $x;
487                                } else {
488                                    if ($x > $ex) {
489                                        $ex = $x;
490                                    }
491                                }
492                            }
493                        }
494                    }
495                }
496                $nx = abs($ex - $sx);
497                $ny = abs($ey - $sy);
498                $img = imagecreate(max($nx + 4, 1), max($ny + 4, 1));
499                $white = $this->getBackColor($img);
500                imagefilledrectangle($img, 0, 0, $nx + 4, $ny + 4, $white);
501                imagecopy($img, $tmpImg, 2, 2, $sx, $sy, min($nx + 2, $tmpWidth - $sx), min($ny + 2, $tmpHeight - $sy));
502                break;
503            case '_hat':
504                $font = $dirFonts . "/" . $fontsMath[$text] . ".ttf";
505                $t = $high;
506                $text = $symbols[$text];
507                $tmpDim = imagettfbbox($t, 0, $font, $text);
508                $tmpWidth = abs($tmpDim[2] - $tmpDim[0]);
509                $tmpHeight = abs($tmpDim[3] - $tmpDim[5]) * 4;
510                $tmpImg = imagecreate(max($tmpWidth, 1), max($tmpHeight, 1));
511                $tmpBlack = $this->getFontColor($tmpImg);
512                $tmpWhite = $this->getBackColor($tmpImg);
513                imagefilledrectangle($tmpImg, 0, 0, $tmpWidth, $tmpHeight, $tmpWhite);
514                imagettftext($tmpImg, $t, 0, 0, $tmpHeight, $tmpBlack, $font, $text);
515                $allWhite = true;
516                $img = $tmpImg;
517                $sx = $sy = $ex = $ey = -1;
518                for ($y = 0; $y < $tmpHeight; $y++) {
519                    for ($x = 0; $x < $tmpWidth; $x++) {
520                        $rgb = imagecolorat($tmpImg, $x, $y);
521                        if ($rgb != $tmpWhite) {
522                            $allWhite = false;
523                            if ($sy == -1) {
524                                $sy = $y;
525                            } else {
526                                $ey = $y;
527                            }
528
529                            if ($sx == -1) {
530                                $sx = $x;
531                            } else {
532                                if ($x < $sx) {
533                                    $sx = $x;
534                                } else {
535                                    if ($x > $ex) {
536                                        $ex = $x;
537                                    }
538                                }
539                            }
540                        }
541                    }
542                }
543                $nx = abs($ex - $sx);
544                $ny = abs($ey - $sy);
545                $img = imagecreate(max($nx + 4, 1), max($ny + 4, 1));
546                $white = $this->getBackColor($img);
547                imagefilledrectangle($img, 0, 0, $nx + 4, $ny + 4, $white);
548                imagecopy($img, $tmpImg, 2, 2, $sx, $sy, min($nx + 2, $tmpWidth - $sx), min($ny + 2, $tmpHeight - $sy));
549                break;
550            case '_dintegrale':
551            case '_tintegrale':
552            if (isset($fontsMath[$text])) {
553                $font = $dirFonts . "/" . $fontsMath[$text] . ".ttf";
554            } elseif ($this->isNumber($text)) {
555                $font = $dirFonts . "/cmr10.ttf";
556            } else {
557                $font = $dirFonts . "/cmmi10.ttf";
558            }
559                $t = 6;
560            if (isset($symbols[$text])) {
561                $text = $symbols[$text];
562            }
563                do {
564                    $tmpDim = imagettfbbox($t, 0, $font, $text);
565                    $t += 1;
566                } while ((abs($tmpDim[3] - $tmpDim[5]) < 1.2 * $high));
567                $tmpWidth = abs($tmpDim[2] - $tmpDim[0]) * 2;
568                $tmpHeight = abs($tmpDim[3] - $tmpDim[5]) * 2;
569                $tmpImg = imagecreate(max($tmpWidth, 1), max($tmpHeight, 1));
570                $tmpBlack = $this->getFontColor($tmpImg);
571                $tmpWhite = $this->getBackColor($tmpImg);
572                imagefilledrectangle($tmpImg, 0, 0, $tmpWidth, $tmpHeight, $tmpWhite);
573                imagettftext($tmpImg, $t, 0, 5, $tmpHeight / 2, $tmpBlack, $font, $text);
574                $img = $tmpImg;
575                $allWhite = true;
576                $sx = $sy = $ex = $ey = -1;
577                for ($y = 0; $y < $tmpHeight; $y++) {
578                    for ($x = 0; $x < $tmpWidth; $x++) {
579                        $rgb = imagecolorat($tmpImg, $x, $y);
580                        if ($rgb != $tmpWhite) {
581                            $allWhite = false;
582                            if ($sy == -1) {
583                                $sy = $y;
584                            } else {
585                                $ey = $y;
586                            }
587
588                            if ($sx == -1) {
589                                $sx = $x;
590                            } else {
591                                if ($x < $sx) {
592                                    $sx = $x;
593                                } else {
594                                    if ($x > $ex) {
595                                        $ex = $x;
596                                    }
597                                }
598                            }
599                        }
600                    }
601                }
602                $nx = abs($ex - $sx);
603                $ny = abs($ey - $sy);
604                if ($allWhite) {
605                    $img = imagecreate(1, max($high, 1));
606                    $white = $this->getBackColor($img);
607                    imagefilledrectangle($img, 0, 0, 1, $high, $white);
608                } else {
609                    $img = imagecreate(max($nx + 4, 1), max($ny + 4, 1));
610                    $white = $this->getBackColor($img);
611                    imagefilledrectangle($img, 0, 0, $nx + 4, $ny + 4, $white);
612                    imagecopy(
613                        $img,
614                        $tmpImg,
615                        2,
616                        2,
617                        $sx,
618                        $sy,
619                        min($nx + 2, $tmpWidth - $sx),
620                        min($ny + 2, $tmpHeight - $sy)
621                    );
622                }
623                break;
624            default:
625                if (isset($fontsMath[$text])) {
626                    $font = $dirFonts . "/" . $fontsMath[$text] . ".ttf";
627                } elseif ($this->isNumber($text)) {
628                    $font = $dirFonts . "/cmr10.ttf";
629                } else {
630                    $font = $dirFonts . "/cmmi10.ttf";
631                }
632                $t = 6;
633                if (isset($symbols[$text])) {
634                    $text = $symbols[$text];
635                }
636                do {
637                    $tmpDim = imagettfbbox($t, 0, $font, $text);
638                    $t += 1;
639                } while ((abs($tmpDim[3] - $tmpDim[5]) < $high));
640                $tmpWidth = abs($tmpDim[2] - $tmpDim[0]) * 2;
641                $tmpHeight = abs($tmpDim[3] - $tmpDim[5]) * 2;
642                $tmpImg = imagecreate(max($tmpWidth, 1), max($tmpHeight, 1));
643                $tmpBlack = $this->getFontColor($tmpImg);
644                $tmpWhite = $this->getBackColor($tmpImg);
645                imagefilledrectangle($tmpImg, 0, 0, $tmpWidth, $tmpHeight, $tmpWhite);
646                imagettftext($tmpImg, $t, 0, 0, $tmpHeight / 4, $tmpBlack, $font, $text);
647                // 	imagettftext($tmpImg, $t, 0,5,5,$tmpBlack, $font,$text);
648                //	$img=$tmpImg;
649                $allWhite = true;
650                $sx = $sy = $ex = $ey = -1;
651                for ($y = 0; $y < $tmpHeight; $y++) {
652                    for ($x = 0; $x < $tmpWidth; $x++) {
653                        $rgb = imagecolorat($tmpImg, $x, $y);
654                        if ($rgb != $tmpWhite) {
655                            $allWhite = false;
656                            if ($sy == -1) {
657                                $sy = $y;
658                            } else {
659                                $ey = $y;
660                            }
661
662                            if ($sx == -1) {
663                                $sx = $x;
664                            } else {
665                                if ($x < $sx) {
666                                    $sx = $x;
667                                } else {
668                                    if ($x > $ex) {
669                                        $ex = $x;
670                                    }
671                                }
672                            }
673                        }
674                    }
675                }
676                $nx = abs($ex - $sx);
677                $ny = abs($ey - $sy);
678                if ($allWhite) {
679                    $img = imagecreate(1, max($high, 1));
680                    $white = $this->getBackColor($img);
681                    imagefilledrectangle($img, 0, 0, 1, $high, $white);
682                } else {
683                    $img = imagecreate(max($nx + 4, 1), max($ny + 4, 1));
684                    $white = $this->getBackColor($img);
685                    imagefilledrectangle($img, 0, 0, $nx + 4, $ny + 4, $white);
686                    imagecopy(
687                        $img,
688                        $tmpImg,
689                        2,
690                        2,
691                        $sx,
692                        $sy,
693                        min($nx + 2, $tmpWidth - $sx),
694                        min($ny + 2, $tmpHeight - $sy)
695                    );
696                }
697                break;
698        }
699
700        //$rouge=imagecolorallocate($img,255,0,0);
701        //ImageRectangle($img,0,0,ImageSX($img)-1,ImageSY($img)-1,$rouge);
702        return $img;
703    }
704
705    /**
706     * @param $text
707     * @param $size
708     * @return resource
709     */
710    public function displayText($text, $size)
711    {
712        $dirFonts = $this->getDirFonts();
713        $size = max($size, 6);
714        $text = stripslashes($text);
715        $font = $dirFonts . "/cmr10.ttf";
716        $textHeight = 'dg' . $text;
717        $heightDim = imagettfbbox($size, 0, $font, $textHeight);
718        $widthDim = imagettfbbox($size, 0, $font, $text);
719        $dx = max($widthDim[2], $widthDim[4]) - min($widthDim[0], $widthDim[6]) + ceil($size / 8);
720        $dy = max($heightDim[1], $heightDim[3]) - min($heightDim[5], $heightDim[7]) + ceil($size / 8);
721        $img = imagecreate(max($dx, 1), max($dy, 1));
722        $black = $this->getFontColor($img);
723        $white = $this->getBackColor($img);
724        imagefilledrectangle($img, 0, 0, $dx, $dy, $white);
725        //ImageRectangle($img,0,0,$dx-1,$dy-1,$black);
726        imagettftext($img, $size, $angle, 0, -min($heightDim[5], $heightDim[7]), $black, $font, $text);
727
728        return $img;
729    }
730
731    /**
732     * @param $text
733     * @param $size
734     * @return resource
735     */
736    public function displayMath($text, $size)
737    {
738        $size = max($size, 6);
739        $symbols = $this->getSymbols();
740        $fontsMath = $this->getMathFonts();
741        $dirFonts = $this->getDirFonts();
742        $text = stripslashes($text);
743        if (isset($fontsMath[$text])) {
744            $font = $dirFonts . "/" . $fontsMath[$text] . ".ttf";
745        } elseif (preg_match("#[a-zA-Z]#", $text)) {
746            $font = $dirFonts . "/cmmi10.ttf";
747        } else {
748            $font = $dirFonts . "/cmr10.ttf";
749        }
750        if (isset($symbols[$text])) {
751            $text = $symbols[$text];
752        }
753        $textHeight = 'dg' . $text;
754        $heightDim = imagettfbbox($size, 0, $font, $textHeight);
755        $widthDim = imagettfbbox($size, 0, $font, $text);
756        $dx = max($widthDim[2], $widthDim[4]) - min($widthDim[0], $widthDim[6]) + ceil($size / 8);
757        $dy = max($heightDim[1], $heightDim[3]) - min($heightDim[5], $heightDim[7]) + ceil($size / 8);
758        $img = imagecreate(max($dx, 1), max($dy, 1));
759        $black = $this->getFontColor($img);
760        $white = $this->getBackColor($img);
761        imagefilledrectangle($img, 0, 0, $dx, $dy, $white);
762        //ImageRectangle($img,0,0,$dx-1,$dy-1,$black);
763        imagettftext($img, $size, 0, 0, -min($heightDim[5], $heightDim[7]), $black, $font, $text);
764
765        return $img;
766    }
767
768    /**
769     * @param $height
770     * @param $style
771     * @return resource
772     */
773    public function parenthesis($height, $style)
774    {
775        $image = $this->displaySymbol($style, $height);
776
777        return $image;
778    }
779
780    /**
781     * @param $image1
782     * @param $base1
783     * @param $image2
784     * @param $base2
785     * @return resource
786     */
787    public function alignment2($image1, $base1, $image2, $base2)
788    {
789        $width1 = imagesx($image1);
790        $height1 = imagesy($image1);
791        $width2 = imagesx($image2);
792        $height2 = imagesy($image2);
793        $top = max($base1, $base2);
794        $bottom = max($height1 - $base1, $height2 - $base2);
795        $width = $width1 + $width2;
796        $height = $top + $bottom;
797        $result = imagecreate(max($width, 1), max($height, 1));
798        $white = $this->getBackColor($result);
799        imagefilledrectangle($result, 0, 0, $width - 1, $height - 1, $white);
800        imagecopy($result, $image1, 0, $top - $base1, 0, 0, $width1, $height1);
801        imagecopy($result, $image2, $width1, $top - $base2, 0, 0, $width2, $height2);
802
803        //ImageRectangle($result,0,0,$width-1,$height-1,$black);
804        return $result;
805    }
806
807    /**
808     * @param $image1
809     * @param $base1
810     * @param $image2
811     * @param $base2
812     * @param $image3
813     * @param $base3
814     * @return resource
815     */
816    public function alignment3($image1, $base1, $image2, $base2, $image3, $base3)
817    {
818        $width1 = imagesx($image1);
819        $height1 = imagesy($image1);
820        $width2 = imagesx($image2);
821        $height2 = imagesy($image2);
822        $width3 = imagesx($image3);
823        $height3 = imagesy($image3);
824        $top = max($base1, $base2, $base3);
825        $bottom = max($height1 - $base1, $height2 - $base2, $height3 - $base3);
826        $width = $width1 + $width2 + $width3;
827        $height = $top + $bottom;
828        $result = imagecreate(max($width, 1), max($height, 1));
829        $black = $this->getFontColor($result);
830        $white = $this->getBackColor($result);
831        imagefilledrectangle($result, 0, 0, $width - 1, $height - 1, $white);
832        imagecopy($result, $image1, 0, $top - $base1, 0, 0, $width1, $height1);
833        imagecopy($result, $image2, $width1, $top - $base2, 0, 0, $width2, $height2);
834        imagecopy($result, $image3, $width1 + $width2, $top - $base3, 0, 0, $width3, $height3);
835
836        //ImageRectangle($result,0,0,$width-1,$height-1,$black);
837        return $result;
838    }
839
840    /**
841     * Set the background color
842     *
843     * @param int $R
844     * @param int $G
845     * @param int $B
846     */
847    public function setBack($R, $G, $B) {
848        $this->backR = $R;
849        $this->backG = $G;
850        $this->backB = $B;
851    }
852
853    /**
854     * Set the font color
855     *
856     * @param int $R
857     * @param int $G
858     * @param int $B
859     */
860    public function setFont($R, $G, $B) {
861        $this->fontR = $R;
862        $this->fontG = $G;
863        $this->fontB = $B;
864    }
865
866    /**
867     * Get the background color allocated for the given image ressource
868     *
869     * @param resource $img
870     * @return int
871     */
872    public function getBackColor($img) {
873        $back = imagecolorallocate($img, $this->backR, $this->backG, $this->backB);
874        if($this->transparent) {
875            $back = imagecolortransparent($img, $back);
876        }
877        return $back;
878    }
879
880    /**
881     * Get the font color allocated for the given image ressource
882     *
883     * @param resource $img
884     * @return int
885     */
886    public function getFontColor($img) {
887        return imagecolorallocate($img, $this->fontR, $this->fontG, $this->fontB);
888    }
889
890
891    /**
892     * @param $dirFonts
893     */
894    public function setDirFonts($dirFonts)
895    {
896        $this->dirFonts = $dirFonts;
897    }
898
899    /**
900     * @return string
901     */
902    public function getDirFonts()
903    {
904        return $this->dirFonts;
905    }
906
907    /**
908     * @param $dirImg
909     */
910    public function setDirImg($dirImg)
911    {
912        $this->dirImg = $dirImg;
913    }
914
915    /**
916     * @return string
917     */
918    public function getDirImg()
919    {
920        return $this->dirImg;
921    }
922
923    /**
924     * @param $mathFonts
925     */
926    public function setMathFonts($mathFonts)
927    {
928        $this->mathFonts = $mathFonts;
929    }
930
931    /**
932     * @return array
933     */
934    public function getMathFonts()
935    {
936        return $this->mathFonts;
937    }
938
939    /**
940     * @param $symbols
941     */
942    public function setSymbols($symbols)
943    {
944        $this->symbols = $symbols;
945    }
946
947    /**
948     * @return array
949     */
950    public function getSymbols()
951    {
952        return $this->symbols;
953    }
954
955    /**
956     * @param $transparent
957     */
958    public function setTransparent($transparent)
959    {
960        $this->transparent = $transparent;
961    }
962
963    /**
964     * @return bool
965     */
966    public function getTransparent()
967    {
968        return $this->transparent;
969    }
970
971}
972