Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
<?php
2
    // latex.php
3
    // render TeX stuff using latex - this will not work on all platforms
4
    // or configurations. Only works on Linux and Mac with appropriate
5
    // software installed.
6
    // Much of this inspired/copied from Benjamin Zeiss' work
7
 
8
    class latex {
9
 
10
        var $temp_dir;
11
        var $error;
12
 
13
        /** @var bool To store value of supported_platform. */
14
        protected $supported_platform;
15
 
16
        /**
17
         * Constructor - create temporary directories and build paths to
18
         * external 'helper' binaries.
19
         * Other platforms could/should be added
20
         */
21
        public function __construct() {
22
            // Construct directory structure.
23
            $this->temp_dir = make_request_directory();
24
        }
25
 
26
        /**
27
         * Old syntax of class constructor. Deprecated in PHP7.
28
         *
29
         * @deprecated since Moodle 3.1
30
         */
31
        public function latex() {
32
            debugging('Use of class name as constructor is deprecated', DEBUG_DEVELOPER);
33
            self::__construct();
34
        }
35
 
36
        /**
37
         * Accessor function for support_platform field.
38
         * @return boolean value of supported_platform
39
         */
40
        function supported() {
41
            return $this->supported_platform;
42
        }
43
 
44
        /**
45
         * Turn the bit of TeX into a valid latex document
46
         * @param string $forumula the TeX formula
47
         * @param int $fontsize the font size
48
         * @return string the latex document
49
         */
50
        function construct_latex_document($formula, $fontsize = 12) {
51
            // $fontsize don't affects to formula's size. $density can change size
52
            $doc = "\\documentclass[{$fontsize}pt]{article}\n";
53
            $doc .= get_config('filter_tex', 'latexpreamble');
54
            $doc .= "\\pagestyle{empty}\n";
55
            $doc .= "\\begin{document}\n";
56
            if (preg_match("/^[[:space:]]*\\\\begin\\{(gather|align|alignat|multline).?\\}/i", $formula)) {
57
               $doc .= "$formula\n";
58
            } else {
59
               $doc .= "$ {$formula} $\n";
60
            }
61
            $doc .= "\\end{document}\n";
62
 
63
            // Sanitize the whole document (rather than just the formula) to make sure no one can bypass sanitization
64
            // by using \newcommand in preamble to give an alias to a blocked command.
65
            $doc = filter_tex_sanitize_formula($doc);
66
 
67
            return $doc;
68
        }
69
 
70
        /**
71
         * execute an external command, with optional logging
72
         * @param string $command command to execute
73
         * @param file $log valid open file handle - log info will be written to this file
74
         * @return return code from execution of command
75
         */
76
        function execute($command, $log=null ) {
77
            $output = array();
78
            exec( $command, $output, $return_code );
79
            if ($log) {
80
                fwrite( $log, "COMMAND: $command \n" );
81
                $outputs = implode( "\n", $output );
82
                fwrite( $log, "OUTPUT: $outputs \n" );
83
                fwrite( $log, "RETURN_CODE: $return_code\n " );
84
            }
85
            return $return_code;
86
        }
87
 
88
        /**
89
         * Render TeX string into gif/png
90
         * @param string $formula TeX formula
91
         * @param string $filename filename for output (including extension)
92
         * @param int $fontsize font size
93
         * @param int $density density value for .ps to .gif/.png conversion
94
         * @param string $background background color (e.g, #FFFFFF).
95
         * @param file $log valid open file handle for optional logging (debugging only)
96
         * @return bool true if successful
97
         */
98
        function render($formula, $filename, $fontsize=12, $density=240, $background='', $log=null ) {
99
 
100
            global $CFG;
101
 
102
            // quick check - will this work?
103
            $pathlatex = get_config('filter_tex', 'pathlatex');
104
            if (empty($pathlatex)) {
105
                return false;
106
            }
107
            $pathlatex = escapeshellarg(trim($pathlatex, " '\""));
108
 
109
            $doc = $this->construct_latex_document( $formula, $fontsize );
110
 
111
            // construct some file paths
112
            $convertformat = get_config('filter_tex', 'convertformat');
113
            if (!strpos($filename, ".{$convertformat}")) {
114
                $convertformat = 'png';
115
            }
116
            $filename = str_replace(".{$convertformat}", '', $filename);
117
            $tex = "$filename.tex"; // Absolute paths won't work with openin_any = p setting.
118
            $dvi = "{$this->temp_dir}/$filename.dvi";
119
            $ps  = "{$this->temp_dir}/$filename.ps";
120
            $img = "{$this->temp_dir}/$filename.{$convertformat}";
121
 
122
            // Change directory to temp dir so that we can work with relative paths.
123
            chdir($this->temp_dir);
124
 
125
            // turn the latex doc into a .tex file in the temp area
126
            $fh = fopen( $tex, 'w' );
127
            fputs( $fh, $doc );
128
            fclose( $fh );
129
 
130
            // run latex on document
131
            $command = "$pathlatex --interaction=nonstopmode --halt-on-error $tex";
132
 
133
            if ($this->execute($command, $log)) { // It allways False on Windows
134
//                return false;
135
            }
136
 
137
            // run dvips (.dvi to .ps)
138
            $pathdvips = escapeshellarg(trim(get_config('filter_tex', 'pathdvips'), " '\""));
139
            $command = "$pathdvips -q -E $dvi -o $ps";
140
            if ($this->execute($command, $log )) {
141
                return false;
142
            }
143
 
144
            // Run convert on document (.ps to .gif/.png) or run dvisvgm (.ps to .svg).
145
            if ($background) {
146
                $bg_opt = "-transparent \"$background\""; // Makes transparent background
147
            } else {
148
                $bg_opt = "";
149
            }
150
            if ($convertformat == 'svg') {
151
                $pathdvisvgm = escapeshellarg(trim(get_config('filter_tex', 'pathdvisvgm'), " '\""));
152
                $command = "$pathdvisvgm -E $ps -o $img";
153
            } else {
154
                $pathconvert = escapeshellarg(trim(get_config('filter_tex', 'pathconvert'), " '\""));
155
                $command = "$pathconvert -density $density -trim $bg_opt $ps $img";
156
            }
157
            if ($this->execute($command, $log )) {
158
                return false;
159
            }
160
 
161
            return $img;
162
        }
163
    }