PageRenderTime 49ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/filter/tex/latex.php

https://gitlab.com/unofficial-mirrors/moodle
PHP | 182 lines | 119 code | 18 blank | 45 comment | 5 complexity | bb581626a2929f12abcb30dac4b71874 MD5 | raw file
  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. class latex {
  8. var $temp_dir;
  9. var $error;
  10. /**
  11. * Constructor - create temporary directories and build paths to
  12. * external 'helper' binaries.
  13. * Other platforms could/should be added
  14. */
  15. public function __construct() {
  16. global $CFG;
  17. // construct directory structure
  18. $this->temp_dir = $CFG->tempdir . "/latex";
  19. make_temp_directory('latex');
  20. }
  21. /**
  22. * Old syntax of class constructor. Deprecated in PHP7.
  23. *
  24. * @deprecated since Moodle 3.1
  25. */
  26. public function latex() {
  27. debugging('Use of class name as constructor is deprecated', DEBUG_DEVELOPER);
  28. self::__construct();
  29. }
  30. /**
  31. * Accessor function for support_platform field.
  32. * @return boolean value of supported_platform
  33. */
  34. function supported() {
  35. return $this->supported_platform;
  36. }
  37. /**
  38. * Turn the bit of TeX into a valid latex document
  39. * @param string $forumula the TeX formula
  40. * @param int $fontsize the font size
  41. * @return string the latex document
  42. */
  43. function construct_latex_document( $formula, $fontsize=12 ) {
  44. global $CFG;
  45. $formula = filter_tex_sanitize_formula($formula);
  46. // $fontsize don't affects to formula's size. $density can change size
  47. $doc = "\\documentclass[{$fontsize}pt]{article}\n";
  48. $doc .= get_config('filter_tex', 'latexpreamble');
  49. $doc .= "\\pagestyle{empty}\n";
  50. $doc .= "\\begin{document}\n";
  51. //dlnsk $doc .= "$ {$formula} $\n";
  52. if (preg_match("/^[[:space:]]*\\\\begin\\{(gather|align|alignat|multline).?\\}/i",$formula)) {
  53. $doc .= "$formula\n";
  54. } else {
  55. $doc .= "$ {$formula} $\n";
  56. }
  57. $doc .= "\\end{document}\n";
  58. return $doc;
  59. }
  60. /**
  61. * execute an external command, with optional logging
  62. * @param string $command command to execute
  63. * @param file $log valid open file handle - log info will be written to this file
  64. * @return return code from execution of command
  65. */
  66. function execute( $command, $log=null ) {
  67. $output = array();
  68. exec( $command, $output, $return_code );
  69. if ($log) {
  70. fwrite( $log, "COMMAND: $command \n" );
  71. $outputs = implode( "\n", $output );
  72. fwrite( $log, "OUTPUT: $outputs \n" );
  73. fwrite( $log, "RETURN_CODE: $return_code\n " );
  74. }
  75. return $return_code;
  76. }
  77. /**
  78. * Render TeX string into gif/png
  79. * @param string $formula TeX formula
  80. * @param string $filename filename for output (including extension)
  81. * @param int $fontsize font size
  82. * @param int $density density value for .ps to .gif/.png conversion
  83. * @param string $background background color (e.g, #FFFFFF).
  84. * @param file $log valid open file handle for optional logging (debugging only)
  85. * @return bool true if successful
  86. */
  87. function render( $formula, $filename, $fontsize=12, $density=240, $background='', $log=null ) {
  88. global $CFG;
  89. // quick check - will this work?
  90. $pathlatex = get_config('filter_tex', 'pathlatex');
  91. if (empty($pathlatex)) {
  92. return false;
  93. }
  94. $pathlatex = escapeshellarg(trim($pathlatex, " '\""));
  95. $doc = $this->construct_latex_document( $formula, $fontsize );
  96. // construct some file paths
  97. $convertformat = get_config('filter_tex', 'convertformat');
  98. if (!strpos($filename, ".{$convertformat}")) {
  99. $convertformat = 'png';
  100. }
  101. $filename = str_replace(".{$convertformat}", '', $filename);
  102. $tex = "{$this->temp_dir}/$filename.tex";
  103. $dvi = "{$this->temp_dir}/$filename.dvi";
  104. $ps = "{$this->temp_dir}/$filename.ps";
  105. $img = "{$this->temp_dir}/$filename.{$convertformat}";
  106. // turn the latex doc into a .tex file in the temp area
  107. $fh = fopen( $tex, 'w' );
  108. fputs( $fh, $doc );
  109. fclose( $fh );
  110. // run latex on document
  111. $command = "$pathlatex --interaction=nonstopmode --halt-on-error $tex";
  112. chdir( $this->temp_dir );
  113. if ($this->execute($command, $log)) { // It allways False on Windows
  114. // return false;
  115. }
  116. // run dvips (.dvi to .ps)
  117. $pathdvips = escapeshellarg(trim(get_config('filter_tex', 'pathdvips'), " '\""));
  118. $command = "$pathdvips -q -E $dvi -o $ps";
  119. if ($this->execute($command, $log )) {
  120. return false;
  121. }
  122. // Run convert on document (.ps to .gif/.png) or run dvisvgm (.ps to .svg).
  123. if ($background) {
  124. $bg_opt = "-transparent \"$background\""; // Makes transparent background
  125. } else {
  126. $bg_opt = "";
  127. }
  128. if ($convertformat == 'svg') {
  129. $pathdvisvgm = escapeshellarg(trim(get_config('filter_tex', 'pathdvisvgm'), " '\""));
  130. $command = "$pathdvisvgm -E $ps -o $img";
  131. } else {
  132. $pathconvert = escapeshellarg(trim(get_config('filter_tex', 'pathconvert'), " '\""));
  133. $command = "$pathconvert -density $density -trim $bg_opt $ps $img";
  134. }
  135. if ($this->execute($command, $log )) {
  136. return false;
  137. }
  138. return $img;
  139. }
  140. /**
  141. * Delete files created in temporary area
  142. * Don't forget to copy the final gif/png before calling this
  143. * @param string $filename file base (no extension)
  144. */
  145. function clean_up( $filename ) {
  146. global $CFG;
  147. unlink( "{$this->temp_dir}/$filename.tex" );
  148. unlink( "{$this->temp_dir}/$filename.dvi" );
  149. unlink( "{$this->temp_dir}/$filename.ps" );
  150. $convertformat = get_config('filter_tex', 'convertformat');
  151. unlink( "{$this->temp_dir}/$filename.{$convertformat}" );
  152. unlink( "{$this->temp_dir}/$filename.aux" );
  153. unlink( "{$this->temp_dir}/$filename.log" );
  154. return;
  155. }
  156. }