MDL-44925 Add SVG output option to TeX notation filter with PNG or MathJax for backup
authorDaniel Thies <dthies@ccal.edu>
Wed, 16 Jul 2014 02:47:22 +0000 (22:47 -0400)
committerDaniel Thies <dthies@ccal.edu>
Wed, 16 Jul 2014 02:47:22 +0000 (22:47 -0400)
filter/tex/filter.php
filter/tex/lang/en/filter_tex.php
filter/tex/latex.php
filter/tex/lib.php
filter/tex/pix.php
filter/tex/settings.php
filter/tex/texdebug.php

index 05eae5d..924837f 100644 (file)
@@ -34,6 +34,8 @@
 
 defined('MOODLE_INTERNAL') || die;
 
+require_once($CFG->libdir . '/classes/useragent.php');
+
 /**
  * Create TeX image link.
  *
@@ -100,6 +102,7 @@ function filter_text_image($imagefile, $tex, $height, $width, $align, $alt) {
         $action = new popup_action('click', $link, 'popup', array('width'=>320,'height'=>240));
     }
     $output = $OUTPUT->action_link($link, $anchorcontents, $action, array('title'=>'TeX')); //TODO: the popups do not work when text caching is enabled!!
+    $output = "<span class=\"MathJax_Preview\">$output</span><script type=\"math/tex\">$tex</script>";
 
     return $output;
 }
@@ -197,6 +200,9 @@ class filter_tex extends moodle_text_filter {
                 $DB->insert_record("cache_filters", $texcache, false);
             }
             $convertformat = get_config('filter_tex', 'convertformat');
+            if ($convertformat == 'svg' && !core_useragent::supports_svg()) {
+                $convertformat = 'png';
+            }
             $filename = $md5.".{$convertformat}";
             $text = str_replace( $matches[0][$i], filter_text_image($filename, $texexp, 0, 0, $align, $alt), $text);
         }
index 49fe7d1..c06a83d 100644 (file)
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 
-$string['configconvertformat'] = 'If <i>latex</i>, <i>dvips</i> and <i>convert</i> are available, the images are created using the specified format. If it is not, mimeTeX will be used and it will create GIF images.';
-$string['convertformat'] = '<i>Convert</i> output format';
+$string['configconvertformat'] = 'If <i>latex</i> and <i>dvips</i> and are available, they are used to GIF or PNG images if <i>convert</i> is also available or if <i>dvisvgm</i> is available SVG images as specified. Otherwise <i>mimeTeX</i> will be used, and it will create GIF images.';
+$string['convertformat'] = 'Output image format';
 $string['latexpreamble'] = 'LaTeX preamble';
 $string['latexsettings'] = 'LaTeX renderer Settings';
 $string['filtername'] = 'TeX notation';
 $string['pathconvert'] = 'Path of <i>convert</i> binary';
 $string['pathdvips'] = 'Path of <i>dvips</i> binary';
+$string['pathdvisvgm'] = 'Path of <i>dvisvgm</i> binary';
 $string['pathlatex'] = 'Path of <i>latex</i> binary';
 $string['pathmimetex'] = 'Path of <i>mimetex</i> binary';
 $string['pathmimetexdesc'] = 'Moodle will use its own mimetex binary unless another valid path is specified.';
index a79a33e..d626a9f 100644 (file)
@@ -78,7 +78,7 @@
         /**
          * Render TeX string into gif/png
          * @param string $formula TeX formula
-         * @param string $filename base of filename for output (no extension)
+         * @param string $filename filename for output (including extension)
          * @param int $fontsize font size
          * @param int $density density value for .ps to .gif/.png conversion
          * @param string $background background color (e.g, #FFFFFF).
             $doc = $this->construct_latex_document( $formula, $fontsize );
 
             // construct some file paths
+            $convertformat = get_config('filter_tex', 'convertformat');
+            if (!strpos($filename, ".{$convertformat}")) {
+                $convertformat = 'png';
+            }
+            $filename = str_replace(".{$convertformat}", '', $filename);
             $tex = "{$this->temp_dir}/$filename.tex";
             $dvi = "{$this->temp_dir}/$filename.dvi";
             $ps  = "{$this->temp_dir}/$filename.ps";
-            $convertformat = get_config('filter_tex', 'convertformat');
             $img = "{$this->temp_dir}/$filename.{$convertformat}";
 
             // turn the latex doc into a .tex file in the temp area
                 return false;
             }
 
-            // run convert on document (.ps to .gif/.png)
+            // Run convert on document (.ps to .gif/.png) or run dvisvgm (.ps to .svg).
             if ($background) {
                 $bg_opt = "-transparent \"$background\""; // Makes transparent background
             } else {
                 $bg_opt = "";
             }
-            $pathconvert = get_config('filter_tex', 'pathconvert');
-            $command = "{$pathconvert} -density $density -trim $bg_opt $ps $img";
+            if ($convertformat == 'svg') {
+                $pathdvisvgm = get_config('filter_tex', 'pathdvisvgm');
+                $command = "{$pathdvisvgm} -E $ps -o $img";
+            } else {
+                $pathconvert = get_config('filter_tex', 'pathconvert');
+                $command = "{$pathconvert} -density $density -trim $bg_opt $ps $img";
+            }
             if ($this->execute($command, $log )) {
                 return false;
             }
index b77dfae..f48bca8 100644 (file)
@@ -127,13 +127,21 @@ function filter_tex_updatedcallback($name) {
 
     $pathdvips = get_config('filter_tex', 'pathdvips');
     $pathconvert = get_config('filter_tex', 'pathconvert');
+    $pathdvisvgm = get_config('filter_tex', 'pathdvisvgm');
 
-    if (!(is_file($pathlatex) && is_executable($pathlatex) &&
-          is_file($pathdvips) && is_executable($pathdvips) &&
-          is_file($pathconvert) && is_executable($pathconvert))) {
-        // LaTeX, dvips or convert are not available, and mimetex can only produce GIFs so...
-        set_config('convertformat', 'gif', 'filter_tex');
+    $supportedformats = array('gif');
+    if ((is_file($pathlatex) && is_executable($pathlatex)) &&
+            (is_file($pathdvips) && is_executable($pathdvips))) {
+        if (is_file($pathconvert) && is_executable($pathconvert)) {
+             $supportedformats[] = 'png';
+        }
+        if (is_file($pathdvisvgm) && is_executable($pathdvisvgm)) {
+             $supportedformats[] = 'svg';
+        }
+    }
+    if (!in_array(get_config('filter_tex', 'convertformat'), $supportedformats)) {
+        set_config('convertformat', array_pop($supportedformats), 'filter_tex');
     }
-}
 
+}
 
index 43c9d1a..d66faf2 100644 (file)
@@ -33,6 +33,9 @@ define('NO_MOODLE_COOKIES', true); // Because it interferes with caching
 
     if (!file_exists($pathname)) {
         $convertformat = get_config('filter_tex', 'convertformat');
+        if (strpos($image, '.png')) {
+            $convertformat = 'png';
+        }
         $md5 = str_replace(".{$convertformat}", '', $image);
         if ($texcache = $DB->get_record('cache_filters', array('filter'=>'tex', 'md5key'=>$md5))) {
             if (!file_exists($CFG->dataroot.'/filter/tex')) {
@@ -44,9 +47,9 @@ define('NO_MOODLE_COOKIES', true); // Because it interferes with caching
             $density = get_config('filter_tex', 'density');
             $background = get_config('filter_tex', 'latexbackground');
             $texexp = $texcache->rawtext; // the entities are now decoded before inserting to DB
-            $latex_path = $latex->render($texexp, $md5, 12, $density, $background);
-            if ($latex_path) {
-                copy($latex_path, $pathname);
+            $lateximage = $latex->render($texexp, $image, 12, $density, $background);
+            if ($lateximage) {
+                copy($lateximage, $pathname);
                 $latex->clean_up($md5);
 
             } else {
index 6c79a21..df82bec 100644 (file)
@@ -39,6 +39,7 @@ if ($ADMIN->fulltree) {
     if (PHP_OS=='Linux') {
         $default_filter_tex_pathlatex   = "/usr/bin/latex";
         $default_filter_tex_pathdvips   = "/usr/bin/dvips";
+        $default_filter_tex_pathdvisvgm = "/usr/bin/dvisvgm";
         $default_filter_tex_pathconvert = "/usr/bin/convert";
 
     } else if (PHP_OS=='Darwin') {
@@ -57,18 +58,20 @@ if ($ADMIN->fulltree) {
     } else {
         $default_filter_tex_pathlatex   = '';
         $default_filter_tex_pathdvips   = '';
+        $default_filter_tex_pathdvisvgm = '';
         $default_filter_tex_pathconvert = '';
     }
 
     $items[] = new admin_setting_configexecutable('filter_tex/pathlatex', get_string('pathlatex', 'filter_tex'), '', $default_filter_tex_pathlatex);
     $items[] = new admin_setting_configexecutable('filter_tex/pathdvips', get_string('pathdvips', 'filter_tex'), '', $default_filter_tex_pathdvips);
     $items[] = new admin_setting_configexecutable('filter_tex/pathconvert', get_string('pathconvert', 'filter_tex'), '', $default_filter_tex_pathconvert);
+    $items[] = new admin_setting_configexecutable('filter_tex/pathdvisvgm', get_string('pathdvisvgm', 'filter_tex'), '', $default_filter_tex_pathdvisvgm);
     $items[] = new admin_setting_configexecutable('filter_tex/pathmimetex', get_string('pathmimetex', 'filter_tex'), get_string('pathmimetexdesc', 'filter_tex'), '');
 
-    // Even if we offer GIF and PNG formats here, in the update callback we check whether
-    // all the paths actually point to executables. If they don't, we force the setting
+    // Even if we offer GIF, PNG and SVG formats here, in the update callback we check whether
+    // required paths actually point to executables. If they don't, we force the setting
     // to GIF, as that's the only format mimeTeX can produce.
-    $formats = array('gif' => 'GIF', 'png' => 'PNG');
+    $formats = array('gif' => 'GIF', 'png' => 'PNG', 'svg' => 'SVG');
     $items[] = new admin_setting_configselect('filter_tex/convertformat', get_string('convertformat', 'filter_tex'), get_string('configconvertformat', 'filter_tex'), 'gif', $formats);
 
     foreach ($items as $item) {
index 51588da..b82e97c 100644 (file)
 
         // first check if it is likely to work at all
         $output .= "<h3>Checking executables</h3>\n";
-        $executables_exist = true;
+        $executablesexist = true;
         $pathlatex = get_config('filter_tex', 'pathlatex');
         if (is_file($pathlatex)) {
             $output .= "latex executable ($pathlatex) is readable<br />\n";
-        }
-        else {
-            $executables_exist = false;
+        } else {
+            $executablesexist = false;
             $output .= "<b>Error:</b> latex executable ($pathlatex) is not readable<br />\n";
         }
         $pathdvips = get_config('filter_tex', 'pathdvips');
         if (is_file($pathdvips)) {
             $output .= "dvips executable ($pathdvips) is readable<br />\n";
-        }
-        else {
-            $executables_exist = false;
+        } else {
+            $executablesexist = false;
             $output .= "<b>Error:</b> dvips executable ($pathdvips) is not readable<br />\n";
         }
         $pathconvert = get_config('filter_tex', 'pathconvert');
         if (is_file($pathconvert)) {
             $output .= "convert executable ($pathconvert) is readable<br />\n";
-        }
-        else {
-            $executables_exist = false;
+        } else {
+            $executablesexist = false;
             $output .= "<b>Error:</b> convert executable ($pathconvert) is not readable<br />\n";
         }
+        $pathdvisvgm = get_config('filter_tex', 'pathdvisvgm');
+        if (is_file($pathdvisvgm)) {
+            $output .= "dvisvgm executable ($pathdvisvgm) is readable<br />\n";
+        } else {
+            $executablesexist = false;
+            $output .= "<b>Error:</b> dvisvgm executable ($pathdvisvgm) is not readable<br />\n";
+        }
 
         // knowing that it might work..
         $md5 = md5($expression);
         $cmd = "$pathdvips -E $dvi -o $ps";
         $output .= execute($cmd);
 
-        // step 3: convert command
-        $cmd = "$pathconvert -density 240 -trim $ps $img ";
+        // Step 3: Set convert or dvisvgm command.
+        if ($convertformat == 'svg') {
+            $cmd = "$pathdvisvgm -E $ps -o $img";
+        } else {
+            $cmd = "$pathconvert -density 240 -trim $ps $img ";
+        }
         $output .= execute($cmd);
 
         if (!$graphic) {
             echo $output;
-        } else if (file_exists($img)){
+        } else if (file_exists($img)) {
             send_file($img, "$md5.{$convertformat}");
         } else {
             echo "Error creating image, see command execution output for more details.";
@@ -338,7 +346,7 @@ searches the database cache_filters table to see if this TeX expression had been
 processed before. If not, it adds a DB entry for that expression.  It then
 replaces the TeX expression by an &lt;img src=&quot;.../filter/tex/pix.php...&quot;&gt;
 tag.  The filter/tex/pix.php script then searches the database to find an
-appropriate gif/png image file for that expression and to create one if it doesn't exist.
+appropriate gif/png/svg image file for that expression and to create one if it doesn't exist.
 It will then use either the LaTex/Ghostscript renderer (using external executables
 on your system) or the bundled Mimetex executable. The full Latex/Ghostscript
 renderer produces better results and is tried first.
@@ -349,7 +357,7 @@ you might try to fix them.</p>
 process this expression. Then the database entry for that expression contains
 a bad TeX expression in the rawtext field (usually blank). You can fix this
 by clicking on &quot;Delete DB Entry&quot;</li>
-<li>The TeX to gif/png image conversion process does not work.
+<li>The TeX to gif/png/svg image conversion process does not work.
 If paths are specified in the filter configuation screen for the three
 executables these will be tried first. Note that they still must be correctly
 installed and have the correct permissions. In particular make sure that you