From 18a2407ef4f245fade0da6863d10fe59258bcb65 Mon Sep 17 00:00:00 2001 From: thepurpleblob Date: Tue, 28 Jun 2005 13:23:57 +0000 Subject: [PATCH] Added class to render images using Latex rather than mimetex. It will only be used if it works on the server, otherwise mimetex is used as before. Produces rather nicer images, and the full range of formatting can be used, rather than mimetex's limited set. --- filter/tex/filter.php | 3 +- filter/tex/latex.php | 161 ++++++++++++++++++++++++++++++++++++++++++ filter/tex/pix.php | 81 ++++++++++++--------- 3 files changed, 208 insertions(+), 37 deletions(-) create mode 100644 filter/tex/latex.php diff --git a/filter/tex/filter.php b/filter/tex/filter.php index 7e076aac97f..78f74192a14 100644 --- a/filter/tex/filter.php +++ b/filter/tex/filter.php @@ -69,7 +69,7 @@ function string_file_picture_tex($imagefile, $tex= "", $height="", $width="", $a $output .= urlencode($tex) . "', 'popup', 'menubar=0,location=0,scrollbars,"; $output .= "resizable,width=300,height=240', 0);\">"; } - $output .= "\"\"slasharguments) { // Use this method if possible for better caching $output .= "$CFG->wwwroot/$CFG->texfilterdir/pix.php/$imagefile"; } else { @@ -108,7 +108,6 @@ function tex_filter ($courseid, $text) { # if ($discussion->forum != 130) { # return $text; # } - $text .= ' '; preg_match_all('/\$(\$\$+?)([^\$])/s',$text,$matches); for ($i=0;$itemp_dir = $CFG->dataroot . "/temp/latex"; + if (!file_exists("$CFG->dataroot/temp")) { + mkdir( "$CFG->dataroot/temp", $CFG->directorypermissions ); + } + if (!file_exists( $this->temp_dir )) { + mkdir( $this->temp_dir, $CFG->directorypermissions ); + } + + // load the paths for the appropriate OS + // it would be nice to expand this + if (PHP_OS=='Linux') { + $binpath = '/usr/bin/'; + $this->supported_platform = true; + } + elseif (PHP_OS=='Darwin') { + $binpath = '/sw/bin/'; // most likely needs a fink install (fink.sf.net) + $this->supported_platform = true; + } + else { + $this->supported_platform = false; + return false; + } + $this->path_latex = "{$binpath}latex"; + $this->path_dvips = "{$binpath}dvips"; + $this->path_convert = "{$binpath}convert"; + $this->path_identify = "{$binpath}identify"; + + return true; + } + + /** + * Turn the bit of TeX into a valid latex document + * @param string $forumula the TeX formula + * @param int $fontsize the font size + * @return string the latex document + */ + function construct_latex_document( $formula, $fontsize=12 ) { + $doc = "\\documentclass[{$fontsize}pt]{article}\n"; + $doc .= "\\usepackage[latin1]{inputenc}\n"; + $doc .= "\\usepackage{amsmath}\n"; + $doc .= "\\usepackage{amsfonts}\n"; + $doc .= "\\pagestyle{empty}\n"; + $doc .= "\\begin{document}\n"; + $doc .= "$ {$formula} $\n"; + $doc .= "\\end{document}\n"; + return $doc; + } + + /** + * execute an external command, with optional logging + * @param string $command command to execute + * @param file $log valid open file handle - log info will be written to this file + * @return return code from execution of command + */ + function execute( $command, $log=null ) { + $output = array(); + exec( $command, $output, $return_code ); + if ($log) { + fwrite( $log, "COMMAND: $command \n" ); + $outputs = implode( "\n", $output ); + fwrite( $log, "OUTPUT: $outputs \n" ); + fwrite( $log, "RETURN_CODE: $return_code\n " ); + } + return $return_code; + } + + /** + * Render TeX string into gif + * @param string $formula TeX formula + * @param string $filename base of filename for output (no extension) + * @param int $fontsize font size + * @param int $density density value for .ps to .gif conversion + * @param string $background background color (e.g, #FFFFFF). + * @param file $log valid open file handle for optional logging (debugging only) + * @return bool true if successful + */ + function render( $formula, $filename, $fontsize=12, $density=240, $background='', $log=null ) { + $doc = $this->construct_latex_document( $formula, $fontsize ); + + // construct some file paths + $tex = "{$this->temp_dir}/$filename.tex"; + $dvi = "{$this->temp_dir}/$filename.dvi"; + $ps = "{$this->temp_dir}/$filename.ps"; + $gif = "{$this->temp_dir}/$filename.gif"; + + // turn the latex doc into a .tex file in the temp area + $fh = fopen( $tex, 'w' ); + fputs( $fh, $doc ); + fclose( $fh ); + + // run latex on document + $command = "{$this->path_latex} --interaction=nonstopmode $tex"; + chdir( $this->temp_dir ); + if ($this->execute($command, $log)) { + return false; + } + + // run dvips (.dvi to .ps) + $command = "{$this->path_dvips} -E $dvi -o $ps"; + if ($this->execute($command, $log )) { + return false; + } + + // run convert on document (.ps to .gif) + if ($background) { + $bg_opt = "-background \"$background\""; + } else { + $bg_opt = ""; + } + $command = "{$this->path_convert} -density $density -trim $bg_opt $ps $gif"; + if ($this->execute($command, $log )) { + return false; + } + + return $gif; + } + + /** + * Delete files created in temporary area + * Don't forget to copy the final gif before calling this + * @param string $filename file base (no extension) + */ + function clean_up( $filename ) { + unlink( "{$this->temp_dir}/$filename.tex" ); + unlink( "{$this->temp_dir}/$filename.dvi" ); + unlink( "{$this->temp_dir}/$filename.ps" ); + unlink( "{$this->temp_dir}/$filename.gif" ); + unlink( "{$this->temp_dir}/$filename.aux" ); + unlink( "{$this->temp_dir}/$filename.log" ); + } + + } + + +?> diff --git a/filter/tex/pix.php b/filter/tex/pix.php index a5f84d3b1bd..e85a07e1d3a 100644 --- a/filter/tex/pix.php +++ b/filter/tex/pix.php @@ -7,6 +7,7 @@ require_once('../../config.php'); require_once($CFG->libdir.'/filelib.php'); + require_once('latex.php'); $CFG->texfilterdir = 'filter/tex'; $CFG->teximagedir = 'filter/tex'; @@ -15,7 +16,7 @@ $cmd = ''; // Initialise these variables $status = ''; - //error_reporting(E_ALL); + error_reporting(E_ALL); $relativepath = get_file_argument('pix.php'); @@ -35,48 +36,58 @@ make_upload_directory($CFG->teximagedir); } - $texexp = $texcache->rawtext; - $texexp = str_replace('<','<',$texexp); - $texexp = str_replace('>','>',$texexp); - $texexp = preg_replace('!\r\n?!',' ',$texexp); - $texexp = '\Large ' . $texexp; + // try and render with latex first + $latex = new latex(); + $latex_path = $latex->render( $texcache->rawtext, $md5, 12, 200, '#FFFFFF' ); + if ($latex_path) { + copy( $latex_path, $pathname ); + $latex->clean_up( $md5 ); + } + else { + // failing that, use mimetex + $texexp = $texcache->rawtext; + $texexp = str_replace('<','<',$texexp); + $texexp = str_replace('>','>',$texexp); + $texexp = preg_replace('!\r\n?!',' ',$texexp); + $texexp = '\Large ' . $texexp; - if ((PHP_OS == "WINNT") || (PHP_OS == "WIN32") || (PHP_OS == "Windows")) { - $texexp = str_replace('"','\"',$texexp); - $cmd = "$CFG->dirroot/$CFG->texfilterdir/mimetex.exe"; - $cmd = str_replace(' ','^ ',$cmd); - $cmd .= " ++ -e \"$pathname\" -- \"$texexp\""; - } else if (is_executable("$CFG->dirroot/$CFG->texfilterdir/mimetex")) { /// Use the custom binary + if ((PHP_OS == "WINNT") || (PHP_OS == "WIN32") || (PHP_OS == "Windows")) { + $texexp = str_replace('"','\"',$texexp); + $cmd = "$CFG->dirroot/$CFG->texfilterdir/mimetex.exe"; + $cmd = str_replace(' ','^ ',$cmd); + $cmd .= " ++ -e \"$pathname\" -- \"$texexp\""; + } else if (is_executable("$CFG->dirroot/$CFG->texfilterdir/mimetex")) { /// Use the custom binary - $cmd = "$CFG->dirroot/$CFG->texfilterdir/mimetex -e $pathname -- ". escapeshellarg($texexp); + $cmd = "$CFG->dirroot/$CFG->texfilterdir/mimetex -e $pathname -- ". escapeshellarg($texexp); - } else { /// Auto-detect the right TeX binary - switch (PHP_OS) { + } else { /// Auto-detect the right TeX binary + switch (PHP_OS) { - case "Linux": - $cmd = "\"$CFG->dirroot/$CFG->texfilterdir/mimetex.linux\" -e \"$pathname\" -- ". escapeshellarg($texexp); - break; + case "Linux": + $cmd = "\"$CFG->dirroot/$CFG->texfilterdir/mimetex.linux\" -e \"$pathname\" -- ". escapeshellarg($texexp); + break; - case "Darwin": - $cmd = "\"$CFG->dirroot/$CFG->texfilterdir/mimetex.darwin\" -e \"$pathname\" -- ". escapeshellarg($texexp); - break; + case "Darwin": + $cmd = "\"$CFG->dirroot/$CFG->texfilterdir/mimetex.darwin\" -e \"$pathname\" -- ". escapeshellarg($texexp); + break; - default: /// Nothing was found, so tell them how to fix it. - if ($CFG->debug > 7) { - echo "Make sure you have an appropriate MimeTeX binary here:\n\n"; - echo " $CFG->dirroot/$CFG->texfilterdir/mimetex\n\n"; - echo "and that it has the right permissions set on it as executable program.\n\n"; - echo "You can get the latest binaries for your ".PHP_OS." platform from: \n\n"; - echo " http://moodle.org/download/mimetex/"; - } else { - echo "Mimetex executable was not found,\n"; - echo "Please turn on debug mode in site configuration to see more info here."; - } - die; - break; + default: /// Nothing was found, so tell them how to fix it. + if ($CFG->debug > 7) { + echo "Make sure you have an appropriate MimeTeX binary here:\n\n"; + echo " $CFG->dirroot/$CFG->texfilterdir/mimetex\n\n"; + echo "and that it has the right permissions set on it as executable program.\n\n"; + echo "You can get the latest binaries for your ".PHP_OS." platform from: \n\n"; + echo " http://moodle.org/download/mimetex/"; + } else { + echo "Mimetex executable was not found,\n"; + echo "Please turn on debug mode in site configuration to see more info here."; + } + die; + break; + } } + system($cmd, $status); } - system($cmd, $status); } }